From 94c67d8420889e950c2f093abdd893ffe3780a97 Mon Sep 17 00:00:00 2001 From: Cosimo Cecchi Date: Thu, 18 Nov 2010 18:45:56 +0100 Subject: [PATCH 01/44] appinfo: add API to get fallback and recommended GAppInfos for a ctype This ways UIs can differentiate between them, and show them in different section. - a recommended app is an application that claims to support a content type directly, not by a supertype derivation. - a fallback app is an application that claims to support a supertype of a given content type. --- gio/gappinfo.h | 3 + gio/gdesktopappinfo.c | 127 +++++++++++++++++++++++++++++++++--------- 2 files changed, 105 insertions(+), 25 deletions(-) diff --git a/gio/gappinfo.h b/gio/gappinfo.h index fc851079e..a52e21644 100644 --- a/gio/gappinfo.h +++ b/gio/gappinfo.h @@ -175,6 +175,9 @@ gboolean g_app_info_delete (GAppInfo *appinfo); GList * g_app_info_get_all (void); GList * g_app_info_get_all_for_type (const char *content_type); +GList * g_app_info_get_recommended_for_type (const gchar *content_type); +GList * g_app_info_get_fallback_for_type (const gchar *content_type); + void g_app_info_reset_type_associations (const char *content_type); GAppInfo *g_app_info_get_default_for_type (const char *content_type, gboolean must_support_uris); diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c index 99a6fb7dd..4a534f781 100644 --- a/gio/gdesktopappinfo.c +++ b/gio/gdesktopappinfo.c @@ -67,7 +67,8 @@ static void g_desktop_app_info_iface_init (GAppInfoIface *iface); static GList * get_all_desktop_entries_for_mime_type (const char *base_mime_type, - const char **except); + const char **except, + gboolean include_fallback); static void mime_info_cache_reload (const char *dir); static gboolean g_desktop_app_info_ensure_saved (GDesktopAppInfo *info, GError **error); @@ -1722,6 +1723,72 @@ app_info_in_list (GAppInfo *info, return FALSE; } +GList * +g_app_info_get_recommended_for_type (const gchar *content_type) +{ + GList *desktop_entries, *l; + GList *infos; + GDesktopAppInfo *info; + + g_return_val_if_fail (content_type != NULL, NULL); + + desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL, FALSE); + + infos = NULL; + for (l = desktop_entries; l != NULL; l = l->next) + { + char *desktop_entry = l->data; + + info = g_desktop_app_info_new (desktop_entry); + if (info) + { + if (app_info_in_list (G_APP_INFO (info), infos)) + g_object_unref (info); + else + infos = g_list_prepend (infos, info); + } + g_free (desktop_entry); + } + + g_list_free (desktop_entries); + + return g_list_reverse (infos); +} + +GList * +g_app_info_get_fallback_for_type (const gchar *content_type) +{ + GList *desktop_entries, *l; + GList *infos, *recommended_infos; + GDesktopAppInfo *info; + + g_return_val_if_fail (content_type != NULL, NULL); + + desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL, TRUE); + recommended_infos = g_app_info_get_recommended_for_type (content_type); + + infos = NULL; + for (l = desktop_entries; l != NULL; l = l->next) + { + char *desktop_entry = l->data; + + info = g_desktop_app_info_new (desktop_entry); + if (info) + { + if (app_info_in_list (G_APP_INFO (info), infos) || + app_info_in_list (G_APP_INFO (info), recommended_infos)) + g_object_unref (info); + else + infos = g_list_prepend (infos, info); + } + g_free (desktop_entry); + } + + g_list_free (desktop_entries); + g_list_free_full (recommended_infos, g_object_unref); + + return g_list_reverse (infos); +} /** * g_app_info_get_all_for_type: @@ -1741,7 +1808,7 @@ g_app_info_get_all_for_type (const char *content_type) g_return_val_if_fail (content_type != NULL, NULL); - desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL); + desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL, TRUE); infos = NULL; for (l = desktop_entries; l != NULL; l = l->next) @@ -1800,7 +1867,7 @@ g_app_info_get_default_for_type (const char *content_type, g_return_val_if_fail (content_type != NULL, NULL); - desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL); + desktop_entries = get_all_desktop_entries_for_mime_type (content_type, NULL, TRUE); info = NULL; for (l = desktop_entries; l != NULL; l = l->next) @@ -2542,7 +2609,8 @@ append_desktop_entry (GList *list, */ static GList * get_all_desktop_entries_for_mime_type (const char *base_mime_type, - const char **except) + const char **except, + gboolean include_fallback) { GList *desktop_entries, *removed_entries, *list, *dir_list, *tmp; MimeInfoCacheDir *dir; @@ -2556,29 +2624,38 @@ get_all_desktop_entries_for_mime_type (const char *base_mime_type, mime_info_cache_init (); - /* collect all ancestors */ - mime_types = _g_unix_content_type_get_parents (base_mime_type); - array = g_ptr_array_new (); - for (i = 0; mime_types[i]; i++) - g_ptr_array_add (array, mime_types[i]); - g_free (mime_types); - for (i = 0; i < array->len; i++) + if (include_fallback) { - anc = _g_unix_content_type_get_parents (g_ptr_array_index (array, i)); - for (j = 0; anc[j]; j++) - { - for (k = 0; k < array->len; k++) - { - if (strcmp (anc[j], g_ptr_array_index (array, k)) == 0) - break; - } - if (k == array->len) /* not found */ - g_ptr_array_add (array, g_strdup (anc[j])); - } - g_strfreev (anc); + /* collect all ancestors */ + mime_types = _g_unix_content_type_get_parents (base_mime_type); + array = g_ptr_array_new (); + for (i = 0; mime_types[i]; i++) + g_ptr_array_add (array, mime_types[i]); + g_free (mime_types); + for (i = 0; i < array->len; i++) + { + anc = _g_unix_content_type_get_parents (g_ptr_array_index (array, i)); + for (j = 0; anc[j]; j++) + { + for (k = 0; k < array->len; k++) + { + if (strcmp (anc[j], g_ptr_array_index (array, k)) == 0) + break; + } + if (k == array->len) /* not found */ + g_ptr_array_add (array, g_strdup (anc[j])); + } + g_strfreev (anc); + } + g_ptr_array_add (array, NULL); + mime_types = (char **)g_ptr_array_free (array, FALSE); + } + else + { + mime_types = g_malloc0 (2 * sizeof (gchar *)); + mime_types[0] = g_strdup (base_mime_type); + mime_types[1] = NULL; } - g_ptr_array_add (array, NULL); - mime_types = (char **)g_ptr_array_free (array, FALSE); G_LOCK (mime_info_cache); From 182fcff2ea2b8f183570d8c026a9ef4d2ec2afdf Mon Sep 17 00:00:00 2001 From: Cosimo Cecchi Date: Thu, 18 Nov 2010 18:49:32 +0100 Subject: [PATCH 02/44] appinfo: only rewrite recommended applications when adding non-default Otherwise you break the fallback + recommended distinction for a content type, as you end up adding support for a given content type to *all* of the applications claiming to support the supertype. --- gio/gdesktopappinfo.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c index 4a534f781..b98e6ac5e 100644 --- a/gio/gdesktopappinfo.c +++ b/gio/gdesktopappinfo.c @@ -1250,10 +1250,10 @@ update_mimeapps_list (const char *desktop_id, add the current list of (not yet listed) apps before it. */ list[i] = NULL; /* Terminate current list so we can use it */ - system_list = get_all_desktop_entries_for_mime_type (content_type, (const char **)list); - + system_list = get_all_desktop_entries_for_mime_type (content_type, (const char **)list, FALSE); + list = g_renew (char *, list, 1 + length + g_list_length (system_list) + 1); - + for (l = system_list; l != NULL; l = l->next) { list[i++] = l->data; /* no strdup, taking ownership */ From 30c378032fe43975dc3ea1014b5b873ef6e3d017 Mon Sep 17 00:00:00 2001 From: Cosimo Cecchi Date: Fri, 19 Nov 2010 10:39:16 +0100 Subject: [PATCH 03/44] appinfo: update docs for API addition --- docs/reference/gio/gio-sections.txt | 2 ++ gio/gdesktopappinfo.c | 22 ++++++++++++++++++++++ gio/gio.symbols | 2 ++ 3 files changed, 26 insertions(+) diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt index 1daec6797..cd515bf52 100644 --- a/docs/reference/gio/gio-sections.txt +++ b/docs/reference/gio/gio-sections.txt @@ -1257,6 +1257,8 @@ g_app_info_get_all g_app_info_get_all_for_type g_app_info_get_default_for_type g_app_info_get_default_for_uri_scheme +g_app_info_get_fallback_for_type +g_app_info_get_recommended_for_type g_app_info_launch_default_for_uri g_app_launch_context_get_display g_app_launch_context_get_startup_notify_id diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c index b98e6ac5e..dfaefc36e 100644 --- a/gio/gdesktopappinfo.c +++ b/gio/gdesktopappinfo.c @@ -1723,6 +1723,17 @@ app_info_in_list (GAppInfo *info, return FALSE; } +/** + * g_app_info_get_recommended_for_type: + * @content_type: the content type to find a #GAppInfo for + * + * Gets a list of recommended #GAppInfos for a given content type, i.e. + * those applications which claim to support the given content type exactly, and + * not by MIME type subclassing. + * + * Returns: (element-type GAppInfo) (transfer full): #GList of #GAppInfos for given @content_type + * or %NULL on error. + **/ GList * g_app_info_get_recommended_for_type (const gchar *content_type) { @@ -1755,6 +1766,17 @@ g_app_info_get_recommended_for_type (const gchar *content_type) return g_list_reverse (infos); } +/** + * g_app_info_get_fallback_for_type: + * @content_type: the content type to find a #GAppInfo for + * + * Gets a list of fallback #GAppInfos for a given content type, i.e. + * those applications which claim to support the given content type by MIME type + * subclassing and not directly. + * + * Returns: (element-type GAppInfo) (transfer full): #GList of #GAppInfos for given @content_type + * or %NULL on error. + **/ GList * g_app_info_get_fallback_for_type (const gchar *content_type) { diff --git a/gio/gio.symbols b/gio/gio.symbols index 90ea290ea..6e2f2322c 100644 --- a/gio/gio.symbols +++ b/gio/gio.symbols @@ -103,6 +103,8 @@ g_app_info_get_all g_app_info_get_all_for_type g_app_info_get_default_for_type g_app_info_get_default_for_uri_scheme +g_app_info_get_fallback_for_type +g_app_info_get_recommended_for_type g_app_info_reset_type_associations #endif #endif From b3bf7a648453e59daa83f745faf9102a90cdfbac Mon Sep 17 00:00:00 2001 From: Cosimo Cecchi Date: Fri, 19 Nov 2010 10:39:33 +0100 Subject: [PATCH 04/44] appinfo: add win32 fallback implementation --- gio/gwin32appinfo.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/gio/gwin32appinfo.c b/gio/gwin32appinfo.c index 8095298bd..a44125151 100644 --- a/gio/gwin32appinfo.c +++ b/gio/gwin32appinfo.c @@ -587,6 +587,28 @@ g_app_info_get_all_for_type (const char *content_type) return g_list_reverse (infos); } +GList * +g_app_info_get_recommended_for_type (const char *content_type) +{ + /* FIXME: this should generate a list of applications that are registered + * as direct handlers for the given content type, without using MIME subclassing. + * See g_app_info_get_recommended_for_type() in gdesktopappinfo.c for a reference + * UNIX implementation. + */ + return g_app_info_get_all_for_type (content_type); +} + +GList * +g_app_info_get_fallback_for_type (const char *content_type) +{ + /* FIXME: this should generate a list of applications that are registered + * as handlers for a superclass of the given content type, but are not + * direct handlers for the content type itself. See g_app_info_get_fallback_for_type() + * in gdesktopappinfo.c for a reference UNIX implementation. + */ + return g_app_info_get_all_for_type (content_type); +} + GAppInfo * g_app_info_get_default_for_type (const char *content_type, gboolean must_support_uris) From 5f958e4623df830f89241b158b14ef7d994cf2c2 Mon Sep 17 00:00:00 2001 From: Cosimo Cecchi Date: Fri, 19 Nov 2010 11:37:44 +0100 Subject: [PATCH 05/44] tests: add a test for recommended and fallback GAppInfos --- gio/tests/desktop-app-info.c | 72 ++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/gio/tests/desktop-app-info.c b/gio/tests/desktop-app-info.c index 62ccd03a7..9d9e181de 100644 --- a/gio/tests/desktop-app-info.c +++ b/gio/tests/desktop-app-info.c @@ -174,6 +174,77 @@ test_default (void) g_object_unref (info2); } +static void +test_fallback (void) +{ + GAppInfo *info1, *info2, *app; + GList *apps, *recomm, *fallback, *list, *l, *m; + GError *error = NULL; + gint old_length; + + info1 = create_app_info ("Test1"); + info2 = create_app_info ("Test2"); + + g_assert (g_content_type_is_a ("text/x-python", "text/plain")); + + apps = g_app_info_get_all_for_type ("text/x-python"); + old_length = g_list_length (apps); + g_list_free_full (apps, g_object_unref); + + g_app_info_set_as_default_for_type (info1, "text/x-python", &error); + g_assert (error == NULL); + + g_app_info_set_as_default_for_type (info2, "text/plain", &error); + g_assert (error == NULL); + + /* check that both apps are registered */ + apps = g_app_info_get_all_for_type ("text/x-python"); + g_assert (g_list_length (apps) == old_length + 2); + + /* check the ordering */ + app = g_list_nth_data (apps, 0); + g_assert (g_app_info_equal (info1, app)); + + app = g_list_nth_data (apps, 1); + g_assert (g_app_info_equal (info2, app)); + + /* check that Test1 is the first recommended app */ + recomm = g_app_info_get_recommended_for_type ("text/x-python"); + g_assert (recomm != NULL); + app = g_list_nth_data (recomm, 0); + g_assert (g_app_info_equal (info1, app)); + + /* and that Test2 is the first fallback */ + fallback = g_app_info_get_fallback_for_type ("text/x-python"); + g_assert (fallback != NULL); + app = g_list_nth_data (fallback, 0); + g_assert (g_app_info_equal (info2, app)); + + /* check that recomm + fallback = all applications */ + list = g_list_concat (g_list_copy (recomm), g_list_copy (fallback)); + g_assert (g_list_length (list) == g_list_length (apps)); + + for (l = list, m = apps; l != NULL && m != NULL; l = l->next, m = m->next) + { + g_assert (g_app_info_equal (l->data, m->data)); + } + + g_list_free (list); + + g_list_free_full (apps, g_object_unref); + g_list_free_full (recomm, g_object_unref); + g_list_free_full (fallback, g_object_unref); + + g_app_info_reset_type_associations ("text/x-python"); + g_app_info_reset_type_associations ("text/plain"); + + g_app_info_delete (info1); + g_app_info_delete (info2); + + g_object_unref (info1); + g_object_unref (info2); +} + static void cleanup_dir_recurse (GFile *parent, GFile *root) { @@ -250,6 +321,7 @@ main (int argc, g_test_add_func ("/desktop-app-info/delete", test_delete); g_test_add_func ("/desktop-app-info/default", test_default); + g_test_add_func ("/desktop-app-info/fallback", test_fallback); result = g_test_run (); From ee94915d0b78da7a016b4df29f0dce6236c1acfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Jard=C3=B3n?= Date: Wed, 24 Nov 2010 18:06:17 +0100 Subject: [PATCH 06/44] docs: gappinfo: Fix typo -> --- gio/gappinfo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gio/gappinfo.c b/gio/gappinfo.c index 941ba2514..755731e58 100644 --- a/gio/gappinfo.c +++ b/gio/gappinfo.c @@ -737,7 +737,7 @@ g_app_launch_context_init (GAppLaunchContext *launch_context) * * Gets the display string for the @context. This is used to ensure new * applications are started on the same display as the launching - * application, by setting the DISPLAY environment variable. + * application, by setting the DISPLAY environment variable. * * Returns: a display string for the display. **/ @@ -766,7 +766,7 @@ g_app_launch_context_get_display (GAppLaunchContext *context, * @files: (element-type GFile): a #GList of of #GFile objects * * Initiates startup notification for the application and returns the - * DESKTOP_STARTUP_ID for the launched operation, + * DESKTOP_STARTUP_ID for the launched operation, * if supported. * * Startup notification IDs are defined in the Date: Wed, 24 Nov 2010 15:57:40 -0500 Subject: [PATCH 07/44] Add Since: tags for new api Also, remove from things like #GAppInfos. gtk-doc learned to deal with this a while ago. --- gio/gdesktopappinfo.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c index dfaefc36e..ce3c8c9ac 100644 --- a/gio/gdesktopappinfo.c +++ b/gio/gdesktopappinfo.c @@ -1727,12 +1727,14 @@ app_info_in_list (GAppInfo *info, * g_app_info_get_recommended_for_type: * @content_type: the content type to find a #GAppInfo for * - * Gets a list of recommended #GAppInfos for a given content type, i.e. - * those applications which claim to support the given content type exactly, and - * not by MIME type subclassing. + * Gets a list of recommended #GAppInfos for a given content type, i.e. + * those applications which claim to support the given content type exactly, + * and not by MIME type subclassing. * - * Returns: (element-type GAppInfo) (transfer full): #GList of #GAppInfos for given @content_type - * or %NULL on error. + * Returns: (element-type GAppInfo) (transfer full): #GList of #GAppInfos + * for given @content_type or %NULL on error. + * + * Since: 2.28 **/ GList * g_app_info_get_recommended_for_type (const gchar *content_type) @@ -1770,12 +1772,14 @@ g_app_info_get_recommended_for_type (const gchar *content_type) * g_app_info_get_fallback_for_type: * @content_type: the content type to find a #GAppInfo for * - * Gets a list of fallback #GAppInfos for a given content type, i.e. - * those applications which claim to support the given content type by MIME type - * subclassing and not directly. + * Gets a list of fallback #GAppInfos for a given content type, i.e. + * those applications which claim to support the given content type + * by MIME type subclassing and not directly. * - * Returns: (element-type GAppInfo) (transfer full): #GList of #GAppInfos for given @content_type - * or %NULL on error. + * Returns: (element-type GAppInfo) (transfer full): #GList of #GAppInfos + * for given @content_type or %NULL on error. + * + * Since: 2.28 **/ GList * g_app_info_get_fallback_for_type (const gchar *content_type) @@ -1816,10 +1820,10 @@ g_app_info_get_fallback_for_type (const gchar *content_type) * g_app_info_get_all_for_type: * @content_type: the content type to find a #GAppInfo for * - * Gets a list of all #GAppInfos for a given content type. + * Gets a list of all #GAppInfos for a given content type. * - * Returns: (element-type GAppInfo) (transfer full): #GList of #GAppInfos for given @content_type - * or %NULL on error. + * Returns: (element-type GAppInfo) (transfer full): #GList of #GAppInfos + * for given @content_type or %NULL on error. **/ GList * g_app_info_get_all_for_type (const char *content_type) From 3570c4a00ef25908172d4d51e30810dddcea1ee8 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Wed, 24 Nov 2010 16:00:32 -0500 Subject: [PATCH 08/44] Add indices for new symbols in 2.28 --- docs/reference/gio/gio-docs.xml | 4 ++++ docs/reference/glib/glib-docs.sgml | 4 ++++ docs/reference/gobject/gobject-docs.sgml | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/docs/reference/gio/gio-docs.xml b/docs/reference/gio/gio-docs.xml index cb03759fb..85c8fabfc 100644 --- a/docs/reference/gio/gio-docs.xml +++ b/docs/reference/gio/gio-docs.xml @@ -232,6 +232,10 @@ Index of new symbols in 2.26 + + Index of new symbols in 2.28 + + diff --git a/docs/reference/glib/glib-docs.sgml b/docs/reference/glib/glib-docs.sgml index 74cc78366..9474af97b 100644 --- a/docs/reference/glib/glib-docs.sgml +++ b/docs/reference/glib/glib-docs.sgml @@ -194,6 +194,10 @@ synchronize their operation. Index of new symbols in 2.26 + + Index of new symbols in 2.28 + + diff --git a/docs/reference/gobject/gobject-docs.sgml b/docs/reference/gobject/gobject-docs.sgml index 686194873..30498ad91 100644 --- a/docs/reference/gobject/gobject-docs.sgml +++ b/docs/reference/gobject/gobject-docs.sgml @@ -148,6 +148,10 @@ Index of new symbols in 2.26 + + Index of new symbols in 2.28 + + From b358202856682e5cdefb0b4b8aaed3a45d9a85fa Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Sat, 6 Nov 2010 09:35:25 -0400 Subject: [PATCH 09/44] gmain: move finalization of GSource outside of context lock This avoids ugly deadlock situations such as in https://bugzilla.gnome.org/show_bug.cgi?id=586432 https://bugzilla.gnome.org/show_bug.cgi?id=626702 https://bugzilla.gnome.org/show_bug.cgi?id=634239 --- glib/gmain.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/glib/gmain.c b/glib/gmain.c index b182c6607..301adb0a7 100644 --- a/glib/gmain.c +++ b/glib/gmain.c @@ -1520,7 +1520,13 @@ g_source_unref_internal (GSource *source, g_source_list_remove (source, context); if (source->source_funcs->finalize) - source->source_funcs->finalize (source); + { + if (context) + UNLOCK_CONTEXT (context); + source->source_funcs->finalize (source); + if (context) + LOCK_CONTEXT (context); + } g_free (source->name); source->name = NULL; From ece936e84dd64af12cb609a8d25f3711a288cc57 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Sat, 6 Nov 2010 09:45:20 -0400 Subject: [PATCH 10/44] gmain: fix some silly code in a programmer-error case Previously if a source got finalized while still attached to a context, it would warn and re-ref the source. But then it just freed it anyway... So keep the warning but drop the re-ref. https://bugzilla.gnome.org/show_bug.cgi?id=634239 --- glib/gmain.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/glib/gmain.c b/glib/gmain.c index 301adb0a7..05b081341 100644 --- a/glib/gmain.c +++ b/glib/gmain.c @@ -1511,13 +1511,12 @@ g_source_unref_internal (GSource *source, source->callback_data = NULL; source->callback_funcs = NULL; - if (context && !SOURCE_DESTROYED (source)) + if (context) { - g_warning (G_STRLOC ": ref_count == 0, but source is still attached to a context!"); - source->ref_count++; + if (!SOURCE_DESTROYED (source)) + g_warning (G_STRLOC ": ref_count == 0, but source was still attached to a context!"); + g_source_list_remove (source, context); } - else if (context) - g_source_list_remove (source, context); if (source->source_funcs->finalize) { From 73d823ac1ee0716568130407a4c164f6c145a75f Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Sun, 7 Nov 2010 11:05:26 -0500 Subject: [PATCH 11/44] Implement closure-related methods for gio GSource types Also, fix up the argument ordering on GFDSourceFunc https://bugzilla.gnome.org/show_bug.cgi?id=634239 --- gio/gasynchelper.c | 59 +++++++++++++++++++++++++++++++++++++++-- gio/gasynchelper.h | 4 +-- gio/gio-marshal.list | 2 ++ gio/gsocket.c | 33 ++++++++++++++++++++++- gio/gunixinputstream.c | 4 +-- gio/gunixoutputstream.c | 4 +-- 6 files changed, 97 insertions(+), 9 deletions(-) diff --git a/gio/gasynchelper.c b/gio/gasynchelper.c index 8e2e8e61a..57590a1ec 100644 --- a/gio/gasynchelper.c +++ b/gio/gasynchelper.c @@ -78,7 +78,7 @@ fd_source_dispatch (GSource *source, g_warn_if_fail (func != NULL); - return (*func) (user_data, fd_source->pollfd.revents, fd_source->pollfd.fd); + return (*func) (fd_source->pollfd.fd, fd_source->pollfd.revents, user_data); } static void @@ -98,11 +98,66 @@ fd_source_finalize (GSource *source) g_object_unref (fd_source->cancellable); } +static gboolean +fd_source_closure_callback (int fd, + GIOCondition condition, + gpointer data) +{ + GClosure *closure = data; + + GValue params[2] = { { 0, }, { 0, } }; + GValue result_value = { 0, }; + gboolean result; + + g_value_init (&result_value, G_TYPE_BOOLEAN); + + g_value_init (¶ms[0], G_TYPE_INT); + g_value_set_int (¶ms[0], fd); + + g_value_init (¶ms[1], G_TYPE_IO_CONDITION); + g_value_set_flags (¶ms[1], condition); + + g_closure_invoke (closure, &result_value, 2, params, NULL); + + result = g_value_get_boolean (&result_value); + g_value_unset (&result_value); + g_value_unset (¶ms[0]); + g_value_unset (¶ms[1]); + + return result; +} + +static void +fd_source_closure_marshal (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + GFDSourceFunc callback; + GCClosure *cc = (GCClosure*) closure; + gboolean v_return; + + g_return_if_fail (return_value != NULL); + g_return_if_fail (n_param_values == 0); + + callback = (GFDSourceFunc) (marshal_data ? marshal_data : cc->callback); + + v_return = callback (g_value_get_int (param_values), + g_value_get_flags (param_values + 1), + closure->data); + + g_value_set_boolean (return_value, v_return); +} + static GSourceFuncs fd_source_funcs = { fd_source_prepare, fd_source_check, fd_source_dispatch, - fd_source_finalize + fd_source_finalize, + (GSourceFunc)fd_source_closure_callback, + (GSourceDummyMarshal)fd_source_closure_marshal, }; /* Might be called on another thread */ diff --git a/gio/gasynchelper.h b/gio/gasynchelper.h index 1e656983d..cd6d28295 100644 --- a/gio/gasynchelper.h +++ b/gio/gasynchelper.h @@ -27,9 +27,9 @@ G_BEGIN_DECLS -typedef gboolean (*GFDSourceFunc) (gpointer user_data, +typedef gboolean (*GFDSourceFunc) (int fd, GIOCondition condition, - int fd); + gpointer user_data); GSource *_g_fd_source_new (int fd, gushort events, diff --git a/gio/gio-marshal.list b/gio/gio-marshal.list index 2cd5ce200..00d16a9f7 100644 --- a/gio/gio-marshal.list +++ b/gio/gio-marshal.list @@ -25,3 +25,5 @@ VOID:POINTER,INT,STRING BOOLEAN:OBJECT INT:OBJECT VOID:INT64 +VOID:UINT64 +BOOLEAN:FLAGS diff --git a/gio/gsocket.c b/gio/gsocket.c index ad0d94033..ae45802b7 100644 --- a/gio/gsocket.c +++ b/gio/gsocket.c @@ -50,6 +50,7 @@ #include "gioerror.h" #include "gioenums.h" #include "gioerror.h" +#include "gio-marshal.h" #include "gnetworkingprivate.h" #include "gsocketaddress.h" #include "gsocketcontrolmessage.h" @@ -2493,12 +2494,42 @@ socket_source_finalize (GSource *source) } } +static gboolean +socket_source_closure_callback (GSocket *socket, + GIOCondition condition, + gpointer data) +{ + GClosure *closure = data; + + GValue params[2] = { { 0, }, { 0, } }; + GValue result_value = { 0, }; + gboolean result; + + g_value_init (&result_value, G_TYPE_BOOLEAN); + + g_value_init (¶ms[0], G_TYPE_SOCKET); + g_value_set_object (¶ms[0], socket); + g_value_init (¶ms[1], G_TYPE_IO_CONDITION); + g_value_set_flags (¶ms[1], condition); + + g_closure_invoke (closure, &result_value, 2, params, NULL); + + result = g_value_get_boolean (&result_value); + g_value_unset (&result_value); + g_value_unset (¶ms[0]); + g_value_unset (¶ms[1]); + + return result; +} + static GSourceFuncs socket_source_funcs = { socket_source_prepare, socket_source_check, socket_source_dispatch, - socket_source_finalize + socket_source_finalize, + (GSourceFunc)socket_source_closure_callback, + (GSourceDummyMarshal)_gio_marshal_BOOLEAN__FLAGS, }; static GSource * diff --git a/gio/gunixinputstream.c b/gio/gunixinputstream.c index 958d0032d..e1ee34ac1 100644 --- a/gio/gunixinputstream.c +++ b/gio/gunixinputstream.c @@ -422,9 +422,9 @@ typedef struct { } ReadAsyncData; static gboolean -read_async_cb (ReadAsyncData *data, +read_async_cb (int fd, GIOCondition condition, - int fd) + ReadAsyncData *data) { GSimpleAsyncResult *simple; GError *error = NULL; diff --git a/gio/gunixoutputstream.c b/gio/gunixoutputstream.c index 5bc1918ad..a0acc318d 100644 --- a/gio/gunixoutputstream.c +++ b/gio/gunixoutputstream.c @@ -409,9 +409,9 @@ typedef struct { } WriteAsyncData; static gboolean -write_async_cb (WriteAsyncData *data, +write_async_cb (int fd, GIOCondition condition, - int fd) + WriteAsyncData *data) { GSimpleAsyncResult *simple; GError *error = NULL; From e910205557b2461eaf1b2ce94176c6525cc716d1 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Sun, 7 Nov 2010 11:49:40 -0500 Subject: [PATCH 12/44] Add g_source_set_dummy_callback() Use g_source_set_closure() and g_close_set_meta_marshal() to allow setting a do-nothing callback on any source. https://bugzilla.gnome.org/show_bug.cgi?id=634239 --- docs/reference/gobject/gobject-sections.txt | 1 + gobject/gobject.symbols | 1 + gobject/gsourceclosure.c | 39 ++++++++++++++++++++- gobject/gsourceclosure.h | 6 ++-- 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/docs/reference/gobject/gobject-sections.txt b/docs/reference/gobject/gobject-sections.txt index 07ef1ded2..9828255a3 100644 --- a/docs/reference/gobject/gobject-sections.txt +++ b/docs/reference/gobject/gobject-sections.txt @@ -828,6 +828,7 @@ g_closure_set_marshal g_closure_add_marshal_guards g_closure_set_meta_marshal g_source_set_closure +g_source_set_dummy_callback G_TYPE_IO_CHANNEL G_TYPE_IO_CONDITION diff --git a/gobject/gobject.symbols b/gobject/gobject.symbols index 9be4f2e82..dd4b62de8 100644 --- a/gobject/gobject.symbols +++ b/gobject/gobject.symbols @@ -128,6 +128,7 @@ g_value_get_flags g_io_channel_get_type g_io_condition_get_type g_source_set_closure +g_source_set_dummy_callback #endif #endif diff --git a/gobject/gsourceclosure.c b/gobject/gsourceclosure.c index 0da50271e..e3e6b8dc8 100644 --- a/gobject/gsourceclosure.c +++ b/gobject/gsourceclosure.c @@ -168,7 +168,7 @@ g_source_set_closure (GSource *source, source->source_funcs != &g_timeout_funcs && source->source_funcs != &g_idle_funcs) { - g_critical (G_STRLOC "closure can not be set on closure without GSourceFuncs::closure_callback\n"); + g_critical (G_STRLOC ": closure can not be set on closure without GSourceFuncs::closure_callback\n"); return; } @@ -191,3 +191,40 @@ g_source_set_closure (GSource *source, g_closure_set_marshal (closure, marshal); } } + +static void +dummy_closure_marshal (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + if (G_VALUE_HOLDS_BOOLEAN (return_value)) + g_value_set_boolean (return_value, TRUE); +} + +/** + * g_source_set_dummy_callback: + * @source: the source + * + * Sets a dummy callback for @source. The callback will do nothing, and + * if the source expects a #gboolean return value, it will return %TRUE. + * (If the source expects any other type of return value, it will return + * a 0/%NULL value; whatever g_value_init() initializes a #GValue to for + * that type.) + * + * If the source is not one of the standard GLib types, the + * @closure_callback and @closure_marshal fields of the #GSourceFuncs + * structure must have been filled in with pointers to appropriate + * functions. + */ +void +g_source_set_dummy_callback (GSource *source) +{ + GClosure *closure; + + closure = g_closure_new_simple (sizeof (GClosure), NULL); + g_closure_set_meta_marshal (closure, NULL, dummy_closure_marshal); + g_source_set_closure (source, closure); +} diff --git a/gobject/gsourceclosure.h b/gobject/gsourceclosure.h index e7f5594fe..edae2c882 100644 --- a/gobject/gsourceclosure.h +++ b/gobject/gsourceclosure.h @@ -27,8 +27,10 @@ G_BEGIN_DECLS -void g_source_set_closure (GSource *source, - GClosure *closure); +void g_source_set_closure (GSource *source, + GClosure *closure); + +void g_source_set_dummy_callback (GSource *source); GType g_io_channel_get_type (void); GType g_io_condition_get_type (void); From d15cdbefecc235cfa431ee7de9c35af174bd1552 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Sat, 6 Nov 2010 10:11:15 -0400 Subject: [PATCH 13/44] gmain: add g_source_add_child_source and g_source_remove_child_source This adds "child source" support to GSource. A child source behaves basically like a GPollFD; when you add a source to a context, all of its child sources are added with the same priority; when you destroy a source, all of its child sources are destroyed; and when a child source triggers, its parent source's dispatch function is run. Use cases include: - adding a GTimeoutSource to another source to cause the source to automatically trigger after a certain timeout. - wrapping an existing source type with a new type that has a different callback signature - creating a source that triggers based on different conditions at different times. https://bugzilla.gnome.org/show_bug.cgi?id=634239 --- docs/reference/glib/glib-sections.txt | 2 + glib/glib.symbols | 2 + glib/gmain.c | 266 +++++++++++++++++++++----- glib/gmain.h | 17 +- 4 files changed, 239 insertions(+), 48 deletions(-) diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt index 1594bc8a9..6540fe8fa 100644 --- a/docs/reference/glib/glib-sections.txt +++ b/docs/reference/glib/glib-sections.txt @@ -535,6 +535,8 @@ GSourceFunc g_source_set_callback_indirect g_source_add_poll g_source_remove_poll +g_source_add_child_source +g_source_remove_child_source g_source_get_time g_source_get_current_time g_source_remove diff --git a/glib/glib.symbols b/glib/glib.symbols index 92f62f2f6..9bb041919 100644 --- a/glib/glib.symbols +++ b/glib/glib.symbols @@ -722,6 +722,7 @@ g_main_loop_quit g_main_loop_ref g_main_loop_run g_main_loop_unref +g_source_add_child_source g_source_add_poll g_source_attach g_source_destroy @@ -739,6 +740,7 @@ g_source_ref g_source_remove g_source_remove_by_funcs_user_data g_source_remove_by_user_data +g_source_remove_child_source g_source_remove_poll g_source_set_callback g_source_set_callback_indirect diff --git a/glib/gmain.c b/glib/gmain.c index 05b081341..b02606795 100644 --- a/glib/gmain.c +++ b/glib/gmain.c @@ -313,6 +313,12 @@ struct _GPollRec gint priority; }; +struct _GSourcePrivate +{ + GSList *child_sources; + GSource *parent_source; +}; + #ifdef G_THREADS_ENABLED #define LOCK_CONTEXT(context) g_static_mutex_lock (&context->mutex) #define UNLOCK_CONTEXT(context) g_static_mutex_unlock (&context->mutex) @@ -344,6 +350,9 @@ static void g_source_unref_internal (GSource *source, static void g_source_destroy_internal (GSource *source, GMainContext *context, gboolean have_lock); +static void g_source_set_priority_unlocked (GSource *source, + GMainContext *context, + gint priority); static void g_main_context_poll (GMainContext *context, gint timeout, gint priority, @@ -848,12 +857,21 @@ g_source_list_add (GSource *source, { GSource *tmp_source, *last_source; - last_source = NULL; - tmp_source = context->source_list; - while (tmp_source && tmp_source->priority <= source->priority) + if (source->priv && source->priv->parent_source) { - last_source = tmp_source; - tmp_source = tmp_source->next; + /* Put the source immediately before its parent */ + tmp_source = source->priv->parent_source; + last_source = source->priv->parent_source->prev; + } + else + { + last_source = NULL; + tmp_source = context->source_list; + while (tmp_source && tmp_source->priority <= source->priority) + { + last_source = tmp_source; + tmp_source = tmp_source->next; + } } source->next = tmp_source; @@ -885,6 +903,39 @@ g_source_list_remove (GSource *source, source->next = NULL; } +static guint +g_source_attach_unlocked (GSource *source, + GMainContext *context) +{ + guint result = 0; + GSList *tmp_list; + + source->context = context; + result = source->source_id = context->next_id++; + + source->ref_count++; + g_source_list_add (source, context); + + tmp_list = source->poll_fds; + while (tmp_list) + { + g_main_context_add_poll_unlocked (context, source->priority, tmp_list->data); + tmp_list = tmp_list->next; + } + + if (source->priv) + { + tmp_list = source->priv->child_sources; + while (tmp_list) + { + g_source_attach_unlocked (tmp_list->data, context); + tmp_list = tmp_list->next; + } + } + + return result; +} + /** * g_source_attach: * @source: a #GSource @@ -901,7 +952,6 @@ g_source_attach (GSource *source, GMainContext *context) { guint result = 0; - GSList *tmp_list; g_return_val_if_fail (source->context == NULL, 0); g_return_val_if_fail (!SOURCE_DESTROYED (source), 0); @@ -911,18 +961,7 @@ g_source_attach (GSource *source, LOCK_CONTEXT (context); - source->context = context; - result = source->source_id = context->next_id++; - - source->ref_count++; - g_source_list_add (source, context); - - tmp_list = source->poll_fds; - while (tmp_list) - { - g_main_context_add_poll_unlocked (context, source->priority, tmp_list->data); - tmp_list = tmp_list->next; - } + result = g_source_attach_unlocked (source, context); #ifdef G_THREADS_ENABLED /* Now wake up the main loop if it is waiting in the poll() */ @@ -972,6 +1011,24 @@ g_source_destroy_internal (GSource *source, tmp_list = tmp_list->next; } } + + if (source->priv && source->priv->child_sources) + { + /* This is safe because even if a child_source finalizer or + * closure notify tried to modify source->priv->child_sources + * from outside the lock, it would fail since + * SOURCE_DESTROYED(source) is now TRUE. + */ + tmp_list = source->priv->child_sources; + while (tmp_list) + { + g_source_destroy_internal (tmp_list->data, context, TRUE); + g_source_unref_internal (tmp_list->data, context, TRUE); + tmp_list = tmp_list->next; + } + g_slist_free (source->priv->child_sources); + source->priv->child_sources = NULL; + } g_source_unref_internal (source, context, TRUE); } @@ -1118,6 +1175,94 @@ g_source_remove_poll (GSource *source, } } +/** + * g_source_add_child_source: + * @source:a #GSource + * @child_source: a second #GSource that @source should "poll" + * + * Adds @child_source to @source as a "polled" source; when @source is + * added to a #GMainContext, @child_source will be automatically added + * with the same priority, when @child_source is triggered, it will + * cause @source to dispatch (and won't call @child_source's own + * callback), and when @source is destroyed, it will destroy + * @child_source as well. (@source will also still be dispatched if + * its own prepare/check functions indicate that it is ready.) + * + * If you need @child_source to do anything on its own when it + * triggers, you can call g_source_set_dummy_callback() on it to set a + * callback that does nothing (except return %TRUE if appropriate). + * + * @source will hold a reference on @child_source while @child_source + * is attached to it. + **/ +void +g_source_add_child_source (GSource *source, + GSource *child_source) +{ + GMainContext *context; + + g_return_if_fail (source != NULL); + g_return_if_fail (child_source != NULL); + g_return_if_fail (!SOURCE_DESTROYED (source)); + g_return_if_fail (!SOURCE_DESTROYED (child_source)); + g_return_if_fail (child_source->context == NULL); + g_return_if_fail (child_source->priv == NULL || child_source->priv->parent_source == NULL); + + context = source->context; + + if (context) + LOCK_CONTEXT (context); + + if (!source->priv) + source->priv = g_slice_new0 (GSourcePrivate); + if (!child_source->priv) + child_source->priv = g_slice_new0 (GSourcePrivate); + + source->priv->child_sources = g_slist_prepend (source->priv->child_sources, + g_source_ref (child_source)); + child_source->priv->parent_source = source; + g_source_set_priority_unlocked (child_source, context, source->priority); + + if (context) + { + UNLOCK_CONTEXT (context); + g_source_attach (child_source, context); + } +} + +/** + * g_source_remove_child_source: + * @source:a #GSource + * @child_source: a #GSource previously passed to + * g_source_add_child_source(). + * + * Detaches @child_source from @source and destroys it. + **/ +void +g_source_remove_child_source (GSource *source, + GSource *child_source) +{ + GMainContext *context; + + g_return_if_fail (source != NULL); + g_return_if_fail (child_source != NULL); + g_return_if_fail (child_source->priv != NULL && child_source->priv->parent_source == source); + g_return_if_fail (!SOURCE_DESTROYED (source)); + g_return_if_fail (!SOURCE_DESTROYED (child_source)); + + context = source->context; + + if (context) + LOCK_CONTEXT (context); + + source->priv->child_sources = g_slist_remove (source->priv->child_sources, child_source); + g_source_destroy_internal (child_source, context, TRUE); + g_source_unref_internal (child_source, context, TRUE); + + if (context) + UNLOCK_CONTEXT (context); +} + /** * g_source_set_callback_indirect: * @source: the source @@ -1263,35 +1408,19 @@ g_source_set_funcs (GSource *source, source->source_funcs = funcs; } -/** - * g_source_set_priority: - * @source: a #GSource - * @priority: the new priority. - * - * Sets the priority of a source. While the main loop is being - * run, a source will be dispatched if it is ready to be dispatched and no sources - * at a higher (numerically smaller) priority are ready to be dispatched. - **/ -void -g_source_set_priority (GSource *source, - gint priority) +static void +g_source_set_priority_unlocked (GSource *source, + GMainContext *context, + gint priority) { GSList *tmp_list; - GMainContext *context; - - g_return_if_fail (source != NULL); - - context = source->context; - - if (context) - LOCK_CONTEXT (context); source->priority = priority; if (context) { /* Remove the source from the context's source and then - * add it back so it is sorted in the correct plcae + * add it back so it is sorted in the correct place */ g_source_list_remove (source, source->context); g_source_list_add (source, source->context); @@ -1307,9 +1436,44 @@ g_source_set_priority (GSource *source, tmp_list = tmp_list->next; } } - - UNLOCK_CONTEXT (source->context); } + + if (source->priv && source->priv->child_sources) + { + tmp_list = source->priv->child_sources; + while (tmp_list) + { + g_source_set_priority_unlocked (tmp_list->data, context, priority); + tmp_list = tmp_list->next; + } + } +} + +/** + * g_source_set_priority: + * @source: a #GSource + * @priority: the new priority. + * + * Sets the priority of a source. While the main loop is being run, a + * source will be dispatched if it is ready to be dispatched and no + * sources at a higher (numerically smaller) priority are ready to be + * dispatched. + **/ +void +g_source_set_priority (GSource *source, + gint priority) +{ + GMainContext *context; + + g_return_if_fail (source != NULL); + + context = source->context; + + if (context) + LOCK_CONTEXT (context); + g_source_set_priority_unlocked (source, context, priority); + if (context) + UNLOCK_CONTEXT (source->context); } /** @@ -2596,7 +2760,15 @@ g_main_context_prepare (GMainContext *context, context->in_check_or_prepare--; if (result) - source->flags |= G_SOURCE_READY; + { + GSource *ready_source = source; + + while (ready_source) + { + ready_source->flags |= G_SOURCE_READY; + ready_source = ready_source->priv ? ready_source->priv->parent_source : NULL; + } + } } if (source->flags & G_SOURCE_READY) @@ -2788,7 +2960,15 @@ g_main_context_check (GMainContext *context, context->in_check_or_prepare--; if (result) - source->flags |= G_SOURCE_READY; + { + GSource *ready_source = source; + + while (ready_source) + { + ready_source->flags |= G_SOURCE_READY; + ready_source = ready_source->priv ? ready_source->priv->parent_source : NULL; + } + } } if (source->flags & G_SOURCE_READY) diff --git a/glib/gmain.h b/glib/gmain.h index 3a7bba08f..bd94651cc 100644 --- a/glib/gmain.h +++ b/glib/gmain.h @@ -53,6 +53,7 @@ typedef struct _GMainLoop GMainLoop; * representing an event source. */ typedef struct _GSource GSource; +typedef struct _GSourcePrivate GSourcePrivate; /** * GSourceCallbackFuncs: @@ -157,7 +158,8 @@ struct _GSource GSource *next; char *name; - gpointer reserved2; + + GSourcePrivate *priv; }; struct _GSourceCallbackFuncs @@ -358,10 +360,15 @@ void g_source_set_callback_indirect (GSource *source, gpointer callback_data, GSourceCallbackFuncs *callback_funcs); -void g_source_add_poll (GSource *source, - GPollFD *fd); -void g_source_remove_poll (GSource *source, - GPollFD *fd); +void g_source_add_poll (GSource *source, + GPollFD *fd); +void g_source_remove_poll (GSource *source, + GPollFD *fd); + +void g_source_add_child_source (GSource *source, + GSource *child_source); +void g_source_remove_child_source (GSource *source, + GSource *child_source); #ifndef G_DISABLE_DEPRECATED void g_source_get_current_time (GSource *source, From 6181c7de36771d4d3bb55785912a934e078b16df Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Sat, 6 Nov 2010 15:49:55 -0400 Subject: [PATCH 14/44] GCancellable: add g_cancellable_create_source() g_cancellable_create_source() returns a GSource that triggers when its corresponding GCancellable is cancelled. This can be used with g_source_add_child_source() to add cancellability to a source. Port gasynchelper's FDSource to use this rather than doing its own cancellable handling, and also fix up its callback argument order to be more normal. https://bugzilla.gnome.org/show_bug.cgi?id=634239 --- docs/reference/gio/gio-sections.txt | 2 + gio/gasynchelper.c | 47 +++-------- gio/gcancellable.c | 116 ++++++++++++++++++++++++++++ gio/gcancellable.h | 2 + gio/gio.symbols | 1 + gio/giotypes.h | 15 ++++ 6 files changed, 146 insertions(+), 37 deletions(-) diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt index cd515bf52..25532adcc 100644 --- a/docs/reference/gio/gio-sections.txt +++ b/docs/reference/gio/gio-sections.txt @@ -1107,6 +1107,8 @@ g_cancellable_set_error_if_cancelled g_cancellable_get_fd g_cancellable_make_pollfd g_cancellable_release_fd +g_cancellable_source_new +GCancellableSourceFunc g_cancellable_get_current g_cancellable_pop_current g_cancellable_push_current diff --git a/gio/gasynchelper.c b/gio/gasynchelper.c index 57590a1ec..fb3d266e3 100644 --- a/gio/gasynchelper.c +++ b/gio/gasynchelper.c @@ -43,18 +43,14 @@ typedef struct { GSource source; GPollFD pollfd; - GCancellable *cancellable; - gulong cancelled_tag; } FDSource; static gboolean fd_source_prepare (GSource *source, gint *timeout) { - FDSource *fd_source = (FDSource *)source; *timeout = -1; - - return g_cancellable_is_cancelled (fd_source->cancellable); + return FALSE; } static gboolean @@ -62,9 +58,7 @@ fd_source_check (GSource *source) { FDSource *fd_source = (FDSource *)source; - return - g_cancellable_is_cancelled (fd_source->cancellable) || - fd_source->pollfd.revents != 0; + return fd_source->pollfd.revents != 0; } static gboolean @@ -84,18 +78,6 @@ fd_source_dispatch (GSource *source, static void fd_source_finalize (GSource *source) { - FDSource *fd_source = (FDSource *)source; - - /* we don't use g_cancellable_disconnect() here, since we are holding - * the main context lock here, and the ::disconnect signal handler - * will try to grab that, and deadlock looms. - */ - if (fd_source->cancelled_tag) - g_signal_handler_disconnect (fd_source->cancellable, - fd_source->cancelled_tag); - - if (fd_source->cancellable) - g_object_unref (fd_source->cancellable); } static gboolean @@ -160,15 +142,6 @@ static GSourceFuncs fd_source_funcs = { (GSourceDummyMarshal)fd_source_closure_marshal, }; -/* Might be called on another thread */ -static void -fd_source_cancelled_cb (GCancellable *cancellable, - gpointer data) -{ - /* Wake up the mainloop in case we're waiting on async calls with FDSource */ - g_main_context_wakeup (NULL); -} - GSource * _g_fd_source_new (int fd, gushort events, @@ -180,18 +153,18 @@ _g_fd_source_new (int fd, source = g_source_new (&fd_source_funcs, sizeof (FDSource)); fd_source = (FDSource *)source; - if (cancellable) - fd_source->cancellable = g_object_ref (cancellable); - fd_source->pollfd.fd = fd; fd_source->pollfd.events = events; g_source_add_poll (source, &fd_source->pollfd); if (cancellable) - fd_source->cancelled_tag = - g_cancellable_connect (cancellable, - (GCallback)fd_source_cancelled_cb, - NULL, NULL); - + { + GSource *cancellable_source = g_cancellable_source_new (cancellable); + + g_source_set_dummy_callback (cancellable_source); + g_source_add_child_source (source, cancellable_source); + g_source_unref (cancellable_source); + } + return source; } diff --git a/gio/gcancellable.c b/gio/gcancellable.c index 3a9953299..65e15bc12 100644 --- a/gio/gcancellable.c +++ b/gio/gcancellable.c @@ -32,6 +32,7 @@ #include #endif #include "gcancellable.h" +#include "gio-marshal.h" #include "glibintl.h" @@ -770,3 +771,118 @@ g_cancellable_disconnect (GCancellable *cancellable, g_signal_handler_disconnect (cancellable, handler_id); G_UNLOCK (cancellable); } + +typedef struct { + GSource source; + + GCancellable *cancellable; + GPollFD pollfd; +} GCancellableSource; + +static gboolean +cancellable_source_prepare (GSource *source, + gint *timeout) +{ + GCancellableSource *cancellable_source = (GCancellableSource *)source; + + *timeout = -1; + return g_cancellable_is_cancelled (cancellable_source->cancellable); +} + +static gboolean +cancellable_source_check (GSource *source) +{ + GCancellableSource *cancellable_source = (GCancellableSource *)source; + + return g_cancellable_is_cancelled (cancellable_source->cancellable); +} + +static gboolean +cancellable_source_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data) +{ + GCancellableSourceFunc func = (GCancellableSourceFunc)callback; + GCancellableSource *cancellable_source = (GCancellableSource *)source; + + return (*func) (cancellable_source->cancellable, user_data); +} + +static void +cancellable_source_finalize (GSource *source) +{ + GCancellableSource *cancellable_source = (GCancellableSource *)source; + + if (cancellable_source->cancellable) + g_object_unref (cancellable_source->cancellable); +} + +static gboolean +cancellable_source_closure_callback (GCancellable *cancellable, + gpointer data) +{ + GClosure *closure = data; + + GValue params = { 0, }; + GValue result_value = { 0, }; + gboolean result; + + g_value_init (&result_value, G_TYPE_BOOLEAN); + + g_value_init (¶ms, G_TYPE_CANCELLABLE); + g_value_set_object (¶ms, cancellable); + + g_closure_invoke (closure, &result_value, 1, ¶ms, NULL); + + result = g_value_get_boolean (&result_value); + g_value_unset (&result_value); + g_value_unset (¶ms); + + return result; +} + +static GSourceFuncs cancellable_source_funcs = +{ + cancellable_source_prepare, + cancellable_source_check, + cancellable_source_dispatch, + cancellable_source_finalize, + (GSourceFunc)cancellable_source_closure_callback, + (GSourceDummyMarshal)_gio_marshal_BOOLEAN__VOID, +}; + +/** + * g_cancellable_source_new: + * @cancellable: a #GCancellable, or %NULL + * + * Creates a source that triggers if @cancellable is cancelled and + * calls its callback of type #GCancellableSourceFunc. This is + * primarily useful for attaching to another (non-cancellable) source + * with g_source_add_child_source() to add cancellability to it. + * + * For convenience, you can call this with a %NULL #GCancellable, + * in which case the source will never trigger. + * + * Return value: the new #GSource. + * + * Since: 2.28 + */ +GSource * +g_cancellable_source_new (GCancellable *cancellable) +{ + GSource *source; + GCancellableSource *cancellable_source; + + source = g_source_new (&cancellable_source_funcs, sizeof (GCancellableSource)); + g_source_set_name (source, "GCancellable"); + cancellable_source = (GCancellableSource *)source; + + if (g_cancellable_make_pollfd (cancellable, + &cancellable_source->pollfd)) + { + cancellable_source->cancellable = g_object_ref (cancellable); + g_source_add_poll (source, &cancellable_source->pollfd); + } + + return source; +} diff --git a/gio/gcancellable.h b/gio/gcancellable.h index dc73ccd32..d8fa63368 100644 --- a/gio/gcancellable.h +++ b/gio/gcancellable.h @@ -83,6 +83,8 @@ gboolean g_cancellable_make_pollfd (GCancellable *cancellable, GPollFD *pollfd); void g_cancellable_release_fd (GCancellable *cancellable); +GSource * g_cancellable_source_new (GCancellable *cancellable); + GCancellable *g_cancellable_get_current (void); void g_cancellable_push_current (GCancellable *cancellable); void g_cancellable_pop_current (GCancellable *cancellable); diff --git a/gio/gio.symbols b/gio/gio.symbols index 6e2f2322c..b417ebae2 100644 --- a/gio/gio.symbols +++ b/gio/gio.symbols @@ -193,6 +193,7 @@ g_cancellable_reset g_cancellable_cancel g_cancellable_connect g_cancellable_disconnect +g_cancellable_source_new #endif #endif diff --git a/gio/giotypes.h b/gio/giotypes.h index ffd38ef26..829d28534 100644 --- a/gio/giotypes.h +++ b/gio/giotypes.h @@ -376,6 +376,21 @@ typedef struct _GDBusPropertyInfo GDBusPropertyInfo; typedef struct _GDBusInterfaceInfo GDBusInterfaceInfo; typedef struct _GDBusNodeInfo GDBusNodeInfo; +/** + * GCancellableSourceFunc: + * @cancellable: the #GCancellable + * @user_data: data passed in by the user. + * + * This is the function type of the callback used for the #GSource + * returned by g_cancellable_source_new(). + * + * Returns: it should return %FALSE if the source should be removed. + * + * Since: 2.28 + */ +typedef gboolean (*GCancellableSourceFunc) (GCancellable *cancellable, + gpointer user_data); + G_END_DECLS #endif /* __GIO_TYPES_H__ */ From c20c2c0abd3bdb1b30b85a586ee6095ed75a7bc2 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Sat, 18 Sep 2010 13:05:25 -0400 Subject: [PATCH 15/44] Add pollable input/output streams When interfacing with APIs that expect unix-style async I/O, it is useful to be able to tell in advance whether a read/write is going to block. This adds new interfaces GPollableInputStream and GPollableOutputStream that can be implemented by a GInputStream or GOutputStream to add _is_readable/_is_writable, _create_source, and _read_nonblocking/_write_nonblocking methods. Also, implement for GUnixInput/OutputStream and GSocketInput/OutputStream https://bugzilla.gnome.org/show_bug.cgi?id=634241 --- docs/reference/gio/gio-docs.xml | 2 + docs/reference/gio/gio-sections.txt | 41 ++++ docs/reference/gio/gio.types | 3 + gio/Makefile.am | 4 + gio/gio.h | 2 + gio/gio.symbols | 21 ++ gio/giotypes.h | 18 ++ gio/gpollableinputstream.c | 304 ++++++++++++++++++++++++++++ gio/gpollableinputstream.h | 101 +++++++++ gio/gpollableoutputstream.c | 201 ++++++++++++++++++ gio/gpollableoutputstream.h | 98 +++++++++ gio/gsocketconnection.c | 3 +- gio/gsocketinputstream.c | 59 +++++- gio/gsocketoutputstream.c | 60 +++++- gio/gunixinputstream.c | 51 ++++- gio/gunixoutputstream.c | 50 ++++- gio/tests/.gitignore | 1 + gio/tests/Makefile.am | 4 + gio/tests/pollable.c | 240 ++++++++++++++++++++++ 19 files changed, 1251 insertions(+), 12 deletions(-) create mode 100644 gio/gpollableinputstream.c create mode 100644 gio/gpollableinputstream.h create mode 100644 gio/gpollableoutputstream.c create mode 100644 gio/gpollableoutputstream.h create mode 100644 gio/tests/pollable.c diff --git a/docs/reference/gio/gio-docs.xml b/docs/reference/gio/gio-docs.xml index 85c8fabfc..f628e45b4 100644 --- a/docs/reference/gio/gio-docs.xml +++ b/docs/reference/gio/gio-docs.xml @@ -68,6 +68,8 @@ + + File types and applications diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt index 25532adcc..68d6b28a8 100644 --- a/docs/reference/gio/gio-sections.txt +++ b/docs/reference/gio/gio-sections.txt @@ -2934,3 +2934,44 @@ G_IS_PERIODIC g_periodic_get_type + +
+gpollableinputstream +GPollableInputStream +GPollableInputStream +GPollableInputStreamInterface + +g_pollable_input_stream_can_poll +g_pollable_input_stream_is_readable +g_pollable_input_stream_create_source +g_pollable_input_stream_read_nonblocking + +GPollableSourceFunc +g_pollable_source_new + +G_POLLABLE_INPUT_STREAM +G_POLLABLE_INPUT_STREAM_GET_INTERFACE +G_IS_POLLABLE_INPUT_STREAM +G_TYPE_POLLABLE_INPUT_STREAM + +g_pollable_input_stream_get_type +
+ +
+gpollableoutputstream +GPollableOutputStream +GPollableOutputStream +GPollableOutputStreamInterface + +g_pollable_output_stream_can_poll +g_pollable_output_stream_is_writable +g_pollable_output_stream_create_source +g_pollable_output_stream_write_nonblocking + +G_POLLABLE_OUTPUT_STREAM +G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE +G_IS_POLLABLE_OUTPUT_STREAM +G_TYPE_POLLABLE_OUTPUT_STREAM + +g_pollable_output_stream_get_type +
diff --git a/docs/reference/gio/gio.types b/docs/reference/gio/gio.types index ec01b40c9..b0472199a 100644 --- a/docs/reference/gio/gio.types +++ b/docs/reference/gio/gio.types @@ -76,6 +76,9 @@ g_output_stream_splice_flags_get_type g_password_save_get_type g_periodic_get_type g_permission_get_type +g_pollable_input_stream_get_type +g_pollable_io_stream_get_type +g_pollable_output_stream_get_type g_proxy_address_enumerator_get_type g_proxy_address_get_type g_proxy_get_type diff --git a/gio/Makefile.am b/gio/Makefile.am index 2aedfc102..5da34b2c6 100644 --- a/gio/Makefile.am +++ b/gio/Makefile.am @@ -349,6 +349,8 @@ libgio_2_0_la_SOURCES = \ goutputstream.c \ gperiodic.c \ gpermission.c \ + gpollableinputstream.c \ + gpollableoutputstream.c \ gpollfilemonitor.c \ gpollfilemonitor.h \ gproxyresolver.c \ @@ -505,6 +507,8 @@ gio_headers = \ goutputstream.h \ gperiodic.h \ gpermission.h \ + gpollableinputstream.h \ + gpollableoutputstream.h \ gproxyaddress.h \ gproxy.h \ gproxyaddressenumerator.h \ diff --git a/gio/gio.h b/gio/gio.h index c18384ff0..0babc7c10 100644 --- a/gio/gio.h +++ b/gio/gio.h @@ -95,6 +95,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/gio/gio.symbols b/gio/gio.symbols index b417ebae2..867cf6385 100644 --- a/gio/gio.symbols +++ b/gio/gio.symbols @@ -1973,3 +1973,24 @@ g_periodic_remove g_periodic_unblock #endif #endif + +#if IN_HEADER(__G_POLLABLE_INPUT_STREAM_H__) +#if IN_FILE(__G_POLLABLE_INPUT_STREAM_C__) +g_pollable_input_stream_get_type G_GNUC_CONST +g_pollable_input_stream_can_poll +g_pollable_input_stream_create_source +g_pollable_input_stream_is_readable +g_pollable_input_stream_read_nonblocking +g_pollable_source_new +#endif +#endif + +#if IN_HEADER(__G_POLLABLE_OUTPUT_STREAM_H__) +#if IN_FILE(__G_POLLABLE_OUTPUT_STREAM_C__) +g_pollable_output_stream_get_type G_GNUC_CONST +g_pollable_output_stream_can_poll +g_pollable_output_stream_create_source +g_pollable_output_stream_is_writable +g_pollable_output_stream_write_nonblocking +#endif +#endif diff --git a/gio/giotypes.h b/gio/giotypes.h index 829d28534..808e84d41 100644 --- a/gio/giotypes.h +++ b/gio/giotypes.h @@ -124,6 +124,8 @@ typedef struct _GNetworkAddress GNetworkAddress; typedef struct _GNetworkService GNetworkService; typedef struct _GOutputStream GOutputStream; typedef struct _GIOStream GIOStream; +typedef struct _GPollableInputStream GPollableInputStream; /* Dummy typedef */ +typedef struct _GPollableOutputStream GPollableOutputStream; /* Dummy typedef */ typedef struct _GResolver GResolver; typedef struct _GSeekable GSeekable; typedef struct _GSimpleAsyncResult GSimpleAsyncResult; @@ -391,6 +393,22 @@ typedef struct _GDBusNodeInfo GDBusNodeInfo; typedef gboolean (*GCancellableSourceFunc) (GCancellable *cancellable, gpointer user_data); +/** + * GPollableSourceFunc: + * @pollable_stream: the #GPollableInputStream or #GPollableOutputStream + * @user_data: data passed in by the user. + * + * This is the function type of the callback used for the #GSource + * returned by g_pollable_input_stream_create_source() and + * g_pollable_output_stream_create_source(). + * + * Returns: it should return %FALSE if the source should be removed. + * + * Since: 2.28 + */ +typedef gboolean (*GPollableSourceFunc) (GObject *pollable_stream, + gpointer user_data); + G_END_DECLS #endif /* __GIO_TYPES_H__ */ diff --git a/gio/gpollableinputstream.c b/gio/gpollableinputstream.c new file mode 100644 index 000000000..19946c666 --- /dev/null +++ b/gio/gpollableinputstream.c @@ -0,0 +1,304 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include "gpollableinputstream.h" +#include "gasynchelper.h" +#include "gio-marshal.h" +#include "glibintl.h" + +/** + * SECTION:gpollableinputstream + * @short_description: Interface for pollable input streams + * @include: gio/gio.h + * @see_also: #GInputStream, #GPollableOutputStream, #GFileDescriptorBased + * + * #GPollableInputStream is implemented by #GInputStreams that + * can be polled for readiness to read. This can be used when + * interfacing with a non-gio API that expects + * unix-file-descriptor-style asynchronous I/O rather than gio-style. + * + * Since: 2.28 + */ + +G_DEFINE_INTERFACE (GPollableInputStream, g_pollable_input_stream, G_TYPE_INPUT_STREAM) + +static gboolean g_pollable_input_stream_default_can_poll (GPollableInputStream *stream); +static gssize g_pollable_input_stream_default_read_nonblocking (GPollableInputStream *stream, + void *buffer, + gsize size, + GError **error); + +static void +g_pollable_input_stream_default_init (GPollableInputStreamInterface *iface) +{ + iface->can_poll = g_pollable_input_stream_default_can_poll; + iface->read_nonblocking = g_pollable_input_stream_default_read_nonblocking; +} + +static gboolean +g_pollable_input_stream_default_can_poll (GPollableInputStream *stream) +{ + return TRUE; +} + +/** + * g_pollable_input_stream_can_poll: + * @stream: a #GPollableInputStream. + * + * Checks if @stream is actually pollable. Some classes may implement + * #GPollableInputStream but have only certain instances of that class + * be pollable. If this method returns %FALSE, then the behavior of + * other #GPollableInputStream methods is undefined. + * + * For any given stream, the value returned by this method is constant; + * a stream cannot switch from pollable to non-pollable or vice versa. + * + * Returns: %TRUE if @stream is pollable, %FALSE if not. + * + * Since: 2.28 + */ +gboolean +g_pollable_input_stream_can_poll (GPollableInputStream *stream) +{ + g_return_val_if_fail (G_IS_POLLABLE_INPUT_STREAM (stream), FALSE); + + return G_POLLABLE_INPUT_STREAM_GET_INTERFACE (stream)->can_poll (stream); +} + +/** + * g_pollable_input_stream_is_readable: + * @stream: a #GPollableInputStream. + * + * Checks if @stream can be read. + * + * Note that some stream types may not be able to implement this 100% + * reliably, and it is possible that a call to g_input_stream_read() + * after this returns %TRUE would still block. To guarantee + * non-blocking behavior, you should always use + * g_pollable_input_stream_read_nonblocking(), which will return a + * %G_IO_ERROR_WOULD_BLOCK error rather than blocking. + * + * Returns: %TRUE if @stream is readable, %FALSE if not. If an error + * has occurred on @stream, this will result in + * g_pollable_input_stream_is_readable() returning %TRUE, and the + * next attempt to read will return the error. + * + * Since: 2.28 + */ +gboolean +g_pollable_input_stream_is_readable (GPollableInputStream *stream) +{ + g_return_val_if_fail (G_IS_POLLABLE_INPUT_STREAM (stream), FALSE); + + return G_POLLABLE_INPUT_STREAM_GET_INTERFACE (stream)->is_readable (stream); +} + +/** + * g_pollable_input_stream_create_source: + * @stream: a #GPollableInputStream. + * @cancellable: a #GCancellable, or %NULL + * + * Creates a #GSource that triggers when @stream can be read, or + * @cancellable is triggered or an error occurs. The callback on the + * source is of the #GPollableSourceFunc type. + * + * As with g_pollable_input_stream_is_readable(), it is possible that + * the stream may not actually be readable even after the source + * triggers, so you should use + * g_pollable_input_stream_read_nonblocking() rather than + * g_input_stream_read() from the callback. + * + * Returns: a new #GSource + * + * Since: 2.28 + */ +GSource * +g_pollable_input_stream_create_source (GPollableInputStream *stream, + GCancellable *cancellable) +{ + g_return_val_if_fail (G_IS_POLLABLE_INPUT_STREAM (stream), NULL); + + return G_POLLABLE_INPUT_STREAM_GET_INTERFACE (stream)-> + create_source (stream, cancellable); +} + +static gssize +g_pollable_input_stream_default_read_nonblocking (GPollableInputStream *stream, + void *buffer, + gsize size, + GError **error) +{ + if (!g_pollable_input_stream_is_readable (stream)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK, + g_strerror (EAGAIN)); + return -1; + } + + return g_input_stream_read (G_INPUT_STREAM (stream), buffer, size, + NULL, error); +} + +/** + * g_pollable_input_stream_read_nonblocking: + * @stream: a #GPollableInputStream + * @buffer: a buffer to read data into (which should be at least @size + * bytes long). + * @size: the number of bytes you want to read + * @cancellable: a #GCancellable, or %NULL + * @error: #GError for error reporting, or %NULL to ignore. + * + * Attempts to read up to @size bytes from @stream into @buffer, as + * with g_input_stream_read(). If @stream is not currently readable, + * this will immediately return %G_IO_ERROR_WOULD_BLOCK, and you can + * use g_pollable_input_stream_create_source() to create a #GSource + * that will be triggered when @stream is readable. + * + * Note that since this method never blocks, you cannot actually + * use @cancellable to cancel it. However, it will return an error + * if @cancellable has already been cancelled when you call, which + * may happen if you call this method after a source triggers due + * to having been cancelled. + * + * Return value: the number of bytes read, or -1 on error (including + * %G_IO_ERROR_WOULD_BLOCK). + */ +gssize +g_pollable_input_stream_read_nonblocking (GPollableInputStream *stream, + void *buffer, + gsize size, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (G_IS_POLLABLE_INPUT_STREAM (stream), -1); + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return -1; + + return G_POLLABLE_INPUT_STREAM_GET_INTERFACE (stream)-> + read_nonblocking (stream, buffer, size, error); +} + +/* GPollableSource */ + +typedef struct { + GSource source; + + GObject *stream; +} GPollableSource; + +static gboolean +pollable_source_prepare (GSource *source, + gint *timeout) +{ + *timeout = -1; + return FALSE; +} + +static gboolean +pollable_source_check (GSource *source) +{ + return FALSE; +} + +static gboolean +pollable_source_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data) +{ + GPollableSourceFunc func = (GPollableSourceFunc)callback; + GPollableSource *pollable_source = (GPollableSource *)source; + + return (*func) (pollable_source->stream, user_data); +} + +static void +pollable_source_finalize (GSource *source) +{ + GPollableSource *pollable_source = (GPollableSource *)source; + + g_object_unref (pollable_source->stream); +} + +static gboolean +pollable_source_closure_callback (GObject *stream, + gpointer data) +{ + GClosure *closure = data; + + GValue param = { 0, }; + GValue result_value = { 0, }; + gboolean result; + + g_value_init (&result_value, G_TYPE_BOOLEAN); + + g_value_init (¶m, G_TYPE_OBJECT); + g_value_set_object (¶m, stream); + + g_closure_invoke (closure, &result_value, 1, ¶m, NULL); + + result = g_value_get_boolean (&result_value); + g_value_unset (&result_value); + g_value_unset (¶m); + + return result; +} + +static GSourceFuncs pollable_source_funcs = +{ + pollable_source_prepare, + pollable_source_check, + pollable_source_dispatch, + pollable_source_finalize, + (GSourceFunc)pollable_source_closure_callback, + (GSourceDummyMarshal)_gio_marshal_BOOLEAN__VOID, +}; + +/** + * g_pollable_source_new: + * @pollable_stream: the stream associated with the new source + * + * Utility method for #GPollableInputStream and #GPollableOutputStream + * implementations. Creates a new #GSource that expects a callback of + * type #GPollableSourceFunc. The new source does not actually do + * anything on its own; use g_source_add_child_source() to add other + * sources to it to cause it to trigger. + * + * Return value: the new #GSource. + * + * Since: 2.28 + */ +GSource * +g_pollable_source_new (GObject *pollable_stream) +{ + GSource *source; + GPollableSource *pollable_source; + + source = g_source_new (&pollable_source_funcs, sizeof (GPollableSource)); + g_source_set_name (source, "GPollableSource"); + pollable_source = (GPollableSource *)source; + pollable_source->stream = g_object_ref (pollable_stream); + + return source; +} diff --git a/gio/gpollableinputstream.h b/gio/gpollableinputstream.h new file mode 100644 index 000000000..5def93ba8 --- /dev/null +++ b/gio/gpollableinputstream.h @@ -0,0 +1,101 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __G_POLLABLE_INPUT_STREAM_H__ +#define __G_POLLABLE_INPUT_STREAM_H__ + +#include + +G_BEGIN_DECLS + +#define G_TYPE_POLLABLE_INPUT_STREAM (g_pollable_input_stream_get_type ()) +#define G_POLLABLE_INPUT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_POLLABLE_INPUT_STREAM, GPollableInputStream)) +#define G_IS_POLLABLE_INPUT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_POLLABLE_INPUT_STREAM)) +#define G_POLLABLE_INPUT_STREAM_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_POLLABLE_INPUT_STREAM, GPollableInputStreamInterface)) + +/** + * GPollableInputStream: + * + * An interface for a #GInputStream that can be polled for readability. + * + * Since: 2.28 + */ +typedef struct _GPollableInputStreamInterface GPollableInputStreamInterface; + +/** + * GPollableInputStreamInterface: + * @g_iface: The parent interface. + * @can_poll: Checks if the #GPollableInputStream instance is actually pollable + * @is_readable: Checks if the stream is readable + * @create_source: Creates a #GSource to poll the stream + * @read_nonblocking: Does a non-blocking read or returns + * %G_IO_ERROR_WOULD_BLOCK + * + * The interface for pollable input streams. + * + * The default implementation of @can_poll always returns %TRUE. + * + * The default implementation of @read_nonblocking calls + * g_pollable_input_stream_is_readable(), and then calls + * g_input_stream_read() if it returns %TRUE. This means you only need + * to override it if it is possible that your @is_readable + * implementation may return %TRUE when the stream is not actually + * readable. + * + * Since: 2.28 + */ +struct _GPollableInputStreamInterface +{ + GTypeInterface g_iface; + + /* Virtual Table */ + gboolean (*can_poll) (GPollableInputStream *stream); + + gboolean (*is_readable) (GPollableInputStream *stream); + GSource * (*create_source) (GPollableInputStream *stream, + GCancellable *cancellable); + gssize (*read_nonblocking) (GPollableInputStream *stream, + void *buffer, + gsize size, + GError **error); +}; + +GType g_pollable_input_stream_get_type (void) G_GNUC_CONST; + +gboolean g_pollable_input_stream_can_poll (GPollableInputStream *stream); + +gboolean g_pollable_input_stream_is_readable (GPollableInputStream *stream); +GSource *g_pollable_input_stream_create_source (GPollableInputStream *stream, + GCancellable *cancellable); + +gssize g_pollable_input_stream_read_nonblocking (GPollableInputStream *stream, + void *buffer, + gsize size, + GCancellable *cancellable, + GError **error); + +/* Helper method for stream implementations */ +GSource *g_pollable_source_new (GObject *stream); + +G_END_DECLS + + +#endif /* __G_POLLABLE_INPUT_STREAM_H__ */ + diff --git a/gio/gpollableoutputstream.c b/gio/gpollableoutputstream.c new file mode 100644 index 000000000..cb9138aad --- /dev/null +++ b/gio/gpollableoutputstream.c @@ -0,0 +1,201 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include "gpollableoutputstream.h" +#include "gasynchelper.h" +#include "gfiledescriptorbased.h" +#include "gio-marshal.h" +#include "glibintl.h" + +/** + * SECTION:gpollableoutputstream + * @short_description: Interface for pollable output streams + * @include: gio/gio.h + * @see_also: #GOutputStream, #GFileDescriptorBased, #GPollableInputStream + * + * #GPollableOutputStream is implemented by #GOutputStreams that + * can be polled for readiness to write. This can be used when + * interfacing with a non-gio API that expects + * unix-file-descriptor-style asynchronous I/O rather than gio-style. + * + * Since: 2.28 + */ + +G_DEFINE_INTERFACE (GPollableOutputStream, g_pollable_output_stream, G_TYPE_OUTPUT_STREAM) + +static gboolean g_pollable_output_stream_default_can_poll (GPollableOutputStream *stream); +static gssize g_pollable_output_stream_default_write_nonblocking (GPollableOutputStream *stream, + const void *buffer, + gsize size, + GError **error); + +static void +g_pollable_output_stream_default_init (GPollableOutputStreamInterface *iface) +{ + iface->can_poll = g_pollable_output_stream_default_can_poll; + iface->write_nonblocking = g_pollable_output_stream_default_write_nonblocking; +} + +static gboolean +g_pollable_output_stream_default_can_poll (GPollableOutputStream *stream) +{ + return TRUE; +} + +/** + * g_pollable_output_stream_can_poll: + * @stream: a #GPollableOutputStream. + * + * Checks if @stream is actually pollable. Some classes may implement + * #GPollableOutputStream but have only certain instances of that + * class be pollable. If this method returns %FALSE, then the behavior + * of other #GPollableOutputStream methods is undefined. + * + * For any given stream, the value returned by this method is constant; + * a stream cannot switch from pollable to non-pollable or vice versa. + * + * Returns: %TRUE if @stream is pollable, %FALSE if not. + * + * Since: 2.28 + */ +gboolean +g_pollable_output_stream_can_poll (GPollableOutputStream *stream) +{ + g_return_val_if_fail (G_IS_POLLABLE_OUTPUT_STREAM (stream), FALSE); + + return G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE (stream)->can_poll (stream); +} + +/** + * g_pollable_output_stream_is_writable: + * @stream: a #GPollableOutputStream. + * + * Checks if @stream can be written. + * + * Note that some stream types may not be able to implement this 100% + * reliably, and it is possible that a call to g_output_stream_write() + * after this returns %TRUE would still block. To guarantee + * non-blocking behavior, you should always use + * g_pollable_output_stream_write_nonblocking(), which will return a + * %G_IO_ERROR_WOULD_BLOCK error rather than blocking. + * + * Returns: %TRUE if @stream is writable, %FALSE if not. If an error + * has occurred on @stream, this will result in + * g_pollable_output_stream_is_writable() returning %TRUE, and the + * next attempt to write will return the error. + * + * Since: 2.28 + */ +gboolean +g_pollable_output_stream_is_writable (GPollableOutputStream *stream) +{ + g_return_val_if_fail (G_IS_POLLABLE_OUTPUT_STREAM (stream), FALSE); + + return G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE (stream)->is_writable (stream); +} + +/** + * g_pollable_output_stream_create_source: + * @stream: a #GPollableOutputStream. + * @cancellable: a #GCancellable, or %NULL + * + * Creates a #GSource that triggers when @stream can be written, or + * @cancellable is triggered or an error occurs. The callback on the + * source is of the #GPollableSourceFunc type. + * + * As with g_pollable_output_stream_is_writable(), it is possible that + * the stream may not actually be writable even after the source + * triggers, so you should use + * g_pollable_output_stream_write_nonblocking() rather than + * g_output_stream_write() from the callback. + * + * Returns: a new #GSource + * + * Since: 2.28 + */ +GSource * +g_pollable_output_stream_create_source (GPollableOutputStream *stream, + GCancellable *cancellable) +{ + g_return_val_if_fail (G_IS_POLLABLE_OUTPUT_STREAM (stream), NULL); + + return G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE (stream)-> + create_source (stream, cancellable); +} + +static gssize +g_pollable_output_stream_default_write_nonblocking (GPollableOutputStream *stream, + const void *buffer, + gsize size, + GError **error) +{ + if (!g_pollable_output_stream_is_writable (stream)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK, + g_strerror (EAGAIN)); + return -1; + } + + return g_output_stream_write (G_OUTPUT_STREAM (stream), buffer, size, + NULL, error); +} + +/** + * g_pollable_output_stream_write_nonblocking: + * @stream: a #GPollableOutputStream + * @buffer: a buffer to write data from + * @size: the number of bytes you want to write + * @cancellable: a #GCancellable, or %NULL + * @error: #GError for error reporting, or %NULL to ignore. + * + * Attempts to write up to @size bytes from @buffer to @stream, as + * with g_output_stream_write(). If @stream is not currently writable, + * this will immediately return %G_IO_ERROR_WOULD_BLOCK, and you can + * use g_pollable_output_stream_create_source() to create a #GSource + * that will be triggered when @stream is writable. + * + * Note that since this method never blocks, you cannot actually + * use @cancellable to cancel it. However, it will return an error + * if @cancellable has already been cancelled when you call, which + * may happen if you call this method after a source triggers due + * to having been cancelled. + * + * Return value: the number of bytes written, or -1 on error (including + * %G_IO_ERROR_WOULD_BLOCK). + */ +gssize +g_pollable_output_stream_write_nonblocking (GPollableOutputStream *stream, + const void *buffer, + gsize size, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (G_IS_POLLABLE_OUTPUT_STREAM (stream), -1); + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return -1; + + return G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE (stream)-> + write_nonblocking (stream, buffer, size, error); +} diff --git a/gio/gpollableoutputstream.h b/gio/gpollableoutputstream.h new file mode 100644 index 000000000..abef0ede6 --- /dev/null +++ b/gio/gpollableoutputstream.h @@ -0,0 +1,98 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __G_POLLABLE_OUTPUT_STREAM_H__ +#define __G_POLLABLE_OUTPUT_STREAM_H__ + +#include + +G_BEGIN_DECLS + +#define G_TYPE_POLLABLE_OUTPUT_STREAM (g_pollable_output_stream_get_type ()) +#define G_POLLABLE_OUTPUT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_POLLABLE_OUTPUT_STREAM, GPollableOutputStream)) +#define G_IS_POLLABLE_OUTPUT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_POLLABLE_OUTPUT_STREAM)) +#define G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_POLLABLE_OUTPUT_STREAM, GPollableOutputStreamInterface)) + +/** + * GPollableOutputStream: + * + * An interface for a #GOutputStream that can be polled for readability. + * + * Since: 2.28 + */ +typedef struct _GPollableOutputStreamInterface GPollableOutputStreamInterface; + +/** + * GPollableOutputStreamInterface: + * @g_iface: The parent interface. + * @can_poll: Checks if the #GPollableOutputStream instance is actually pollable + * @is_writable: Checks if the stream is writable + * @create_source: Creates a #GSource to poll the stream + * @write_nonblocking: Does a non-blocking write or returns + * %G_IO_ERROR_WOULD_BLOCK + * + * The interface for pollable output streams. + * + * The default implementation of @can_poll always returns %TRUE. + * + * The default implementation of @write_nonblocking calls + * g_pollable_output_stream_is_writable(), and then calls + * g_output_stream_write() if it returns %TRUE. This means you only + * need to override it if it is possible that your @is_writable + * implementation may return %TRUE when the stream is not actually + * writable. + * + * Since: 2.28 + */ +struct _GPollableOutputStreamInterface +{ + GTypeInterface g_iface; + + /* Virtual Table */ + gboolean (*can_poll) (GPollableOutputStream *stream); + + gboolean (*is_writable) (GPollableOutputStream *stream); + GSource * (*create_source) (GPollableOutputStream *stream, + GCancellable *cancellable); + gssize (*write_nonblocking) (GPollableOutputStream *stream, + const void *buffer, + gsize size, + GError **error); +}; + +GType g_pollable_output_stream_get_type (void) G_GNUC_CONST; + +gboolean g_pollable_output_stream_can_poll (GPollableOutputStream *stream); + +gboolean g_pollable_output_stream_is_writable (GPollableOutputStream *stream); +GSource *g_pollable_output_stream_create_source (GPollableOutputStream *stream, + GCancellable *cancellable); + +gssize g_pollable_output_stream_write_nonblocking (GPollableOutputStream *stream, + const void *buffer, + gsize size, + GCancellable *cancellable, + GError **error); + +G_END_DECLS + + +#endif /* __G_POLLABLE_OUTPUT_STREAM_H__ */ + diff --git a/gio/gsocketconnection.c b/gio/gsocketconnection.c index 495f81c36..852805af3 100644 --- a/gio/gsocketconnection.c +++ b/gio/gsocketconnection.c @@ -60,8 +60,7 @@ * Since: 2.22 */ -G_DEFINE_TYPE (GSocketConnection, - g_socket_connection, G_TYPE_IO_STREAM); +G_DEFINE_TYPE (GSocketConnection, g_socket_connection, G_TYPE_IO_STREAM); enum { diff --git a/gio/gsocketinputstream.c b/gio/gsocketinputstream.c index 4a27d9034..fb9da1bf1 100644 --- a/gio/gsocketinputstream.c +++ b/gio/gsocketinputstream.c @@ -27,13 +27,18 @@ #include "gsocketinputstream.h" #include "glibintl.h" -#include -#include -#include +#include "gsimpleasyncresult.h" +#include "gcancellable.h" +#include "gpollableinputstream.h" +#include "gioerror.h" +static void g_socket_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface); + #define g_socket_input_stream_get_type _g_socket_input_stream_get_type -G_DEFINE_TYPE (GSocketInputStream, g_socket_input_stream, G_TYPE_INPUT_STREAM); +G_DEFINE_TYPE_WITH_CODE (GSocketInputStream, g_socket_input_stream, G_TYPE_INPUT_STREAM, + G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM, g_socket_input_stream_pollable_iface_init) + ) enum { @@ -205,6 +210,44 @@ g_socket_input_stream_read_finish (GInputStream *stream, return count; } +static gboolean +g_socket_input_stream_pollable_is_readable (GPollableInputStream *pollable) +{ + GSocketInputStream *input_stream = G_SOCKET_INPUT_STREAM (pollable); + + return g_socket_condition_check (input_stream->priv->socket, G_IO_IN); +} + +static GSource * +g_socket_input_stream_pollable_create_source (GPollableInputStream *pollable, + GCancellable *cancellable) +{ + GSocketInputStream *input_stream = G_SOCKET_INPUT_STREAM (pollable); + GSource *socket_source, *pollable_source; + + pollable_source = g_pollable_source_new (G_OBJECT (input_stream)); + socket_source = g_socket_create_source (input_stream->priv->socket, + G_IO_IN, cancellable); + g_source_set_dummy_callback (socket_source); + g_source_add_child_source (pollable_source, socket_source); + g_source_unref (socket_source); + + return pollable_source; +} + +static gssize +g_socket_input_stream_pollable_read_nonblocking (GPollableInputStream *pollable, + void *buffer, + gsize size, + GError **error) +{ + GSocketInputStream *input_stream = G_SOCKET_INPUT_STREAM (pollable); + + return g_socket_receive_with_blocking (input_stream->priv->socket, + buffer, size, FALSE, + NULL, error); +} + static void g_socket_input_stream_class_init (GSocketInputStreamClass *klass) { @@ -229,6 +272,14 @@ g_socket_input_stream_class_init (GSocketInputStreamClass *klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } +static void +g_socket_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface) +{ + iface->is_readable = g_socket_input_stream_pollable_is_readable; + iface->create_source = g_socket_input_stream_pollable_create_source; + iface->read_nonblocking = g_socket_input_stream_pollable_read_nonblocking; +} + static void g_socket_input_stream_init (GSocketInputStream *stream) { diff --git a/gio/gsocketoutputstream.c b/gio/gsocketoutputstream.c index 4febf8803..0ef336016 100644 --- a/gio/gsocketoutputstream.c +++ b/gio/gsocketoutputstream.c @@ -28,14 +28,20 @@ #include "gsocketoutputstream.h" #include "gsocket.h" -#include -#include -#include +#include "gsimpleasyncresult.h" +#include "gcancellable.h" +#include "gpollableinputstream.h" +#include "gpollableoutputstream.h" +#include "gioerror.h" #include "glibintl.h" +static void g_socket_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface); + #define g_socket_output_stream_get_type _g_socket_output_stream_get_type -G_DEFINE_TYPE (GSocketOutputStream, g_socket_output_stream, G_TYPE_OUTPUT_STREAM); +G_DEFINE_TYPE_WITH_CODE (GSocketOutputStream, g_socket_output_stream, G_TYPE_OUTPUT_STREAM, + G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_OUTPUT_STREAM, g_socket_output_stream_pollable_iface_init) + ) enum { @@ -207,6 +213,44 @@ g_socket_output_stream_write_finish (GOutputStream *stream, return count; } +static gboolean +g_socket_output_stream_pollable_is_writable (GPollableOutputStream *pollable) +{ + GSocketOutputStream *output_stream = G_SOCKET_OUTPUT_STREAM (pollable); + + return g_socket_condition_check (output_stream->priv->socket, G_IO_OUT); +} + +static GSource * +g_socket_output_stream_pollable_create_source (GPollableOutputStream *pollable, + GCancellable *cancellable) +{ + GSocketOutputStream *output_stream = G_SOCKET_OUTPUT_STREAM (pollable); + GSource *socket_source, *pollable_source; + + pollable_source = g_pollable_source_new (G_OBJECT (output_stream)); + socket_source = g_socket_create_source (output_stream->priv->socket, + G_IO_OUT, cancellable); + g_source_set_dummy_callback (socket_source); + g_source_add_child_source (pollable_source, socket_source); + g_source_unref (socket_source); + + return pollable_source; +} + +static gssize +g_socket_output_stream_pollable_write_nonblocking (GPollableOutputStream *pollable, + const void *buffer, + gsize size, + GError **error) +{ + GSocketOutputStream *output_stream = G_SOCKET_OUTPUT_STREAM (pollable); + + return g_socket_send_with_blocking (output_stream->priv->socket, + buffer, size, FALSE, + NULL, error); +} + static void g_socket_output_stream_class_init (GSocketOutputStreamClass *klass) { @@ -231,6 +275,14 @@ g_socket_output_stream_class_init (GSocketOutputStreamClass *klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } +static void +g_socket_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface) +{ + iface->is_writable = g_socket_output_stream_pollable_is_writable; + iface->create_source = g_socket_output_stream_pollable_create_source; + iface->write_nonblocking = g_socket_output_stream_pollable_write_nonblocking; +} + static void g_socket_output_stream_init (GSocketOutputStream *stream) { diff --git a/gio/gunixinputstream.c b/gio/gunixinputstream.c index e1ee34ac1..43a924729 100644 --- a/gio/gunixinputstream.c +++ b/gio/gunixinputstream.c @@ -60,7 +60,12 @@ enum { PROP_CLOSE_FD }; -G_DEFINE_TYPE (GUnixInputStream, g_unix_input_stream, G_TYPE_INPUT_STREAM); +static void g_unix_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (GUnixInputStream, g_unix_input_stream, G_TYPE_INPUT_STREAM, + G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM, + g_unix_input_stream_pollable_iface_init) + ); struct _GUnixInputStreamPrivate { int fd; @@ -111,6 +116,9 @@ static gboolean g_unix_input_stream_close_finish (GInputStream *stream, GAsyncResult *result, GError **error); +static gboolean g_unix_input_stream_pollable_is_readable (GPollableInputStream *stream); +static GSource *g_unix_input_stream_pollable_create_source (GPollableInputStream *stream, + GCancellable *cancellable); static void g_unix_input_stream_finalize (GObject *object) @@ -174,6 +182,13 @@ g_unix_input_stream_class_init (GUnixInputStreamClass *klass) G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); } +static void +g_unix_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface) +{ + iface->is_readable = g_unix_input_stream_pollable_is_readable; + iface->create_source = g_unix_input_stream_pollable_create_source; +} + static void g_unix_input_stream_set_property (GObject *object, guint prop_id, @@ -637,3 +652,37 @@ g_unix_input_stream_close_finish (GInputStream *stream, /* Failures handled in generic close_finish code */ return TRUE; } + +static gboolean +g_unix_input_stream_pollable_is_readable (GPollableInputStream *stream) +{ + GUnixInputStream *unix_stream = G_UNIX_INPUT_STREAM (stream); + GPollFD poll_fd; + gint result; + + poll_fd.fd = unix_stream->priv->fd; + poll_fd.events = G_IO_IN; + + do + result = g_poll (&poll_fd, 1, 0); + while (result == -1 && errno == EINTR); + + return poll_fd.revents != 0; +} + +static GSource * +g_unix_input_stream_pollable_create_source (GPollableInputStream *stream, + GCancellable *cancellable) +{ + GUnixInputStream *unix_stream = G_UNIX_INPUT_STREAM (stream); + GSource *inner_source, *pollable_source; + + pollable_source = g_pollable_source_new (G_OBJECT (stream)); + + inner_source = _g_fd_source_new (unix_stream->priv->fd, G_IO_IN, cancellable); + g_source_set_dummy_callback (inner_source); + g_source_add_child_source (pollable_source, inner_source); + g_source_unref (inner_source); + + return pollable_source; +} diff --git a/gio/gunixoutputstream.c b/gio/gunixoutputstream.c index a0acc318d..81021be8e 100644 --- a/gio/gunixoutputstream.c +++ b/gio/gunixoutputstream.c @@ -60,8 +60,12 @@ enum { PROP_CLOSE_FD }; -G_DEFINE_TYPE (GUnixOutputStream, g_unix_output_stream, G_TYPE_OUTPUT_STREAM); +static void g_unix_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface); +G_DEFINE_TYPE_WITH_CODE (GUnixOutputStream, g_unix_output_stream, G_TYPE_OUTPUT_STREAM, + G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_OUTPUT_STREAM, + g_unix_output_stream_pollable_iface_init) + ); struct _GUnixOutputStreamPrivate { int fd; @@ -103,6 +107,9 @@ static gboolean g_unix_output_stream_close_finish (GOutputStream *stream, GAsyncResult *result, GError **error); +static gboolean g_unix_output_stream_pollable_is_writable (GPollableOutputStream *stream); +static GSource *g_unix_output_stream_pollable_create_source (GPollableOutputStream *stream, + GCancellable *cancellable); static void g_unix_output_stream_finalize (GObject *object) @@ -160,6 +167,13 @@ g_unix_output_stream_class_init (GUnixOutputStreamClass *klass) G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); } +static void +g_unix_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface) +{ + iface->is_writable = g_unix_output_stream_pollable_is_writable; + iface->create_source = g_unix_output_stream_pollable_create_source; +} + static void g_unix_output_stream_set_property (GObject *object, guint prop_id, @@ -593,3 +607,37 @@ g_unix_output_stream_close_finish (GOutputStream *stream, /* Failures handled in generic close_finish code */ return TRUE; } + +static gboolean +g_unix_output_stream_pollable_is_writable (GPollableOutputStream *stream) +{ + GUnixOutputStream *unix_stream = G_UNIX_OUTPUT_STREAM (stream); + GPollFD poll_fd; + gint result; + + poll_fd.fd = unix_stream->priv->fd; + poll_fd.events = G_IO_OUT; + + do + result = g_poll (&poll_fd, 1, 0); + while (result == -1 && errno == EINTR); + + return poll_fd.revents != 0; +} + +static GSource * +g_unix_output_stream_pollable_create_source (GPollableOutputStream *stream, + GCancellable *cancellable) +{ + GUnixOutputStream *unix_stream = G_UNIX_OUTPUT_STREAM (stream); + GSource *inner_source, *pollable_source; + + pollable_source = g_pollable_source_new (G_OBJECT (stream)); + + inner_source = _g_fd_source_new (unix_stream->priv->fd, G_IO_OUT, cancellable); + g_source_set_dummy_callback (inner_source); + g_source_add_child_source (pollable_source, inner_source); + g_source_unref (inner_source); + + return pollable_source; +} diff --git a/gio/tests/.gitignore b/gio/tests/.gitignore index c987b6471..0663fefcd 100644 --- a/gio/tests/.gitignore +++ b/gio/tests/.gitignore @@ -60,6 +60,7 @@ memory-input-stream memory-output-stream network-address org.gtk.test.enums.xml +pollable proxy readwrite resolver diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am index 5e65c08e2..ad2273a42 100644 --- a/gio/tests/Makefile.am +++ b/gio/tests/Makefile.am @@ -43,6 +43,7 @@ TEST_PROGS += \ network-address \ gdbus-message \ socket \ + pollable \ $(NULL) if OS_UNIX @@ -204,6 +205,9 @@ network_address_LDADD = $(progs_ldadd) socket_SOURCE = socket.c socket_LDADD = $(progs_ldadd) +pollable_SOURCE = pollable.c +pollable_LDADD = $(progs_ldadd) + contexts_SOURCES = contexts.c contexts_LDADD = $(progs_ldadd) \ $(top_builddir)/gthread/libgthread-2.0.la diff --git a/gio/tests/pollable.c b/gio/tests/pollable.c new file mode 100644 index 000000000..8669e2b1a --- /dev/null +++ b/gio/tests/pollable.c @@ -0,0 +1,240 @@ +/* GLib testing framework examples and tests + * + * Copyright (C) 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include + +#ifdef G_OS_UNIX +#include +#include +#endif + +GMainLoop *loop; +GPollableInputStream *in; +GOutputStream *out; + +static gboolean +poll_source_callback (GPollableInputStream *in, + gpointer user_data) +{ + GError *error = NULL; + char buf[2]; + gssize nread; + gboolean *success = user_data; + + nread = g_pollable_input_stream_read_nonblocking (in, buf, 2, NULL, &error); + g_assert_no_error (error); + g_assert_cmpint (nread, ==, 2); + g_assert_cmpstr (buf, ==, "x"); + + *success = TRUE; + return FALSE; +} + +static gboolean +check_source_readability_callback (gpointer user_data) +{ + gboolean expected = GPOINTER_TO_INT (user_data); + gboolean readable; + + readable = g_pollable_input_stream_is_readable (in); + g_assert_cmpint (readable, ==, expected); + return FALSE; +} + +static gboolean +write_callback (gpointer user_data) +{ + char *buf = "x"; + gssize nwrote; + GError *error = NULL; + + nwrote = g_output_stream_write (out, buf, 2, NULL, &error); + g_assert_no_error (error); + g_assert_cmpint (nwrote, ==, 2); + + check_source_readability_callback (GINT_TO_POINTER (TRUE)); + + return FALSE; +} + +static gboolean +check_source_and_quit_callback (gpointer user_data) +{ + check_source_readability_callback (user_data); + g_main_loop_quit (loop); + return FALSE; +} + +static void +test_streams (void) +{ + gboolean readable; + GError *error = NULL; + char buf[1]; + gssize nread; + GSource *poll_source; + gboolean success = FALSE; + + readable = g_pollable_input_stream_is_readable (in); + g_assert (!readable); + + nread = g_pollable_input_stream_read_nonblocking (in, buf, 1, NULL, &error); + g_assert_cmpint (nread, ==, -1); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK); + g_clear_error (&error); + + /* Create 4 sources, in decreasing order of priority: + * 1. poll source on @in + * 2. idle source that checks if @in is readable once + * (it won't be) and then removes itself + * 3. idle source that writes a byte to @out, checks that + * @in is now readable, and removes itself + * 4. idle source that checks if @in is readable once + * (it won't be, since the poll source will fire before + * this one does) and then quits the loop. + * + * If the poll source triggers before it should, then it will get a + * %G_IO_ERROR_WOULD_BLOCK, and if check() fails in either + * direction, we will catch it at some point. + */ + + poll_source = g_pollable_input_stream_create_source (in, NULL); + g_source_set_priority (poll_source, 1); + g_source_set_callback (poll_source, (GSourceFunc) poll_source_callback, &success, NULL); + g_source_attach (poll_source, NULL); + g_source_unref (poll_source); + + g_idle_add_full (2, check_source_readability_callback, GINT_TO_POINTER (FALSE), NULL); + g_idle_add_full (3, write_callback, NULL, NULL); + g_idle_add_full (4, check_source_and_quit_callback, GINT_TO_POINTER (FALSE), NULL); + + loop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (loop); + g_main_loop_unref (loop); + + g_assert_cmpint (success, ==, TRUE); +} + +#ifdef G_OS_UNIX +static void +test_pollable_unix (void) +{ + int pipefds[2], status; + + status = pipe (pipefds); + g_assert_cmpint (status, ==, 0); + + in = G_POLLABLE_INPUT_STREAM (g_unix_input_stream_new (pipefds[0], TRUE)); + out = g_unix_output_stream_new (pipefds[1], TRUE); + + test_streams (); + + g_object_unref (in); + g_object_unref (out); +} +#endif + +static void +client_connected (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSocketClient *client = G_SOCKET_CLIENT (source); + GSocketConnection **conn = user_data; + GError *error = NULL; + + *conn = g_socket_client_connect_finish (client, result, &error); + g_assert_no_error (error); +} + +static void +server_connected (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GSocketListener *listener = G_SOCKET_LISTENER (source); + GSocketConnection **conn = user_data; + GError *error = NULL; + + *conn = g_socket_listener_accept_finish (listener, result, NULL, &error); + g_assert_no_error (error); +} + +static void +test_pollable_socket (void) +{ + GInetAddress *iaddr; + GSocketAddress *saddr, *effective_address; + GSocketListener *listener; + GSocketClient *client; + GError *error = NULL; + GSocketConnection *client_conn = NULL, *server_conn = NULL; + + iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4); + saddr = g_inet_socket_address_new (iaddr, 0); + g_object_unref (iaddr); + + listener = g_socket_listener_new (); + g_socket_listener_add_address (listener, saddr, + G_SOCKET_TYPE_STREAM, + G_SOCKET_PROTOCOL_TCP, + NULL, + &effective_address, + &error); + g_assert_no_error (error); + g_object_unref (saddr); + + client = g_socket_client_new (); + + g_socket_client_connect_async (client, + G_SOCKET_CONNECTABLE (effective_address), + NULL, client_connected, &client_conn); + g_socket_listener_accept_async (listener, NULL, + server_connected, &server_conn); + + while (!client_conn || !server_conn) + g_main_context_iteration (NULL, TRUE); + + in = G_POLLABLE_INPUT_STREAM (g_io_stream_get_input_stream (G_IO_STREAM (client_conn))); + out = g_io_stream_get_output_stream (G_IO_STREAM (server_conn)); + + test_streams (); + + g_object_unref (client_conn); + g_object_unref (server_conn); + g_object_unref (client); + g_object_unref (listener); +} + +int +main (int argc, + char *argv[]) +{ + g_type_init (); + g_test_init (&argc, &argv, NULL); + +#ifdef G_OS_UNIX + g_test_add_func ("/pollable/unix", test_pollable_unix); +#endif + g_test_add_func ("/pollable/socket", test_pollable_socket); + + return g_test_run(); +} + From a1690339c731cf037d3ed97eda864159f2ba9308 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Mon, 1 Nov 2010 20:22:24 -0400 Subject: [PATCH 16/44] make GProxyConnection public, as GTcpWrapperConnection GProxyConnection is a class that was added for proxy support; g_socket_client_connect() returns a GSocketConnection, but in some cases (eg, encrypted SOCKS), GProxy might return a GIOStream that is not a GSocketConnection. In that case, GSocketClient would wrap the stream up in a GProxyConnection, which is a subclass of GSocketConnection but uses the input/output streams of the wrapped connection. GTlsConnection is not a GSocketConnection, so it has the same problem, so it will need the same treatment. Rename the class to GTcpWrapperStream, and make it public, so people can extract the base stream from it when necessary. (This is not ideal and GSocketClient will need to be revisited as an API at some point...) https://bugzilla.gnome.org/show_bug.cgi?id=588189 --- docs/reference/gio/gio-docs.xml | 1 + docs/reference/gio/gio-sections.txt | 19 +++ docs/reference/gio/gio.types | 1 + gio/Makefile.am | 4 +- gio/gio.h | 1 + gio/gio.symbols | 8 ++ gio/giotypes.h | 1 + gio/gproxyconnection.c | 155 --------------------- gio/gproxyconnection.h | 69 ---------- gio/gsocketclient.c | 56 ++++---- gio/gtcpwrapperconnection.c | 200 ++++++++++++++++++++++++++++ gio/gtcpwrapperconnection.h | 68 ++++++++++ 12 files changed, 332 insertions(+), 251 deletions(-) delete mode 100644 gio/gproxyconnection.c delete mode 100644 gio/gproxyconnection.h create mode 100644 gio/gtcpwrapperconnection.c create mode 100644 gio/gtcpwrapperconnection.h diff --git a/docs/reference/gio/gio-docs.xml b/docs/reference/gio/gio-docs.xml index f628e45b4..850a58af4 100644 --- a/docs/reference/gio/gio-docs.xml +++ b/docs/reference/gio/gio-docs.xml @@ -120,6 +120,7 @@ + diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt index 68d6b28a8..d6f5aedb2 100644 --- a/docs/reference/gio/gio-sections.txt +++ b/docs/reference/gio/gio-sections.txt @@ -1882,6 +1882,25 @@ GTcpConnectionPrivate g_tcp_connection_get_type +
+gtcpwrapperconnection +GTcpWrapperConnection +GTcpWrapperConnection +g_tcp_wrapper_connection_new +g_tcp_wrapper_connection_get_base_io_stream + +GTcpWrapperConnectionClass +G_IS_TCP_WRAPPER_CONNECTION +G_IS_TCP_WRAPPER_CONNECTION_CLASS +G_TYPE_TCP_WRAPPER_CONNECTION +G_TCP_WRAPPER_CONNECTION +G_TCP_WRAPPER_CONNECTION_CLASS +G_TCP_WRAPPER_CONNECTION_GET_CLASS + +GTcpWrapperConnectionPrivate +g_tcp_wrapper_connection_get_type +
+
gsocketcontrolmessage GSocketControlMessage diff --git a/docs/reference/gio/gio.types b/docs/reference/gio/gio.types index b0472199a..44361788c 100644 --- a/docs/reference/gio/gio.types +++ b/docs/reference/gio/gio.types @@ -105,6 +105,7 @@ g_socket_service_get_type g_socket_type_get_type g_srv_target_get_type g_tcp_connection_get_type +g_tcp_wrapper_connection_get_type g_themed_icon_get_type g_threaded_socket_service_get_type g_unix_connection_get_type diff --git a/gio/Makefile.am b/gio/Makefile.am index 5da34b2c6..b70583a94 100644 --- a/gio/Makefile.am +++ b/gio/Makefile.am @@ -373,11 +373,10 @@ libgio_2_0_la_SOURCES = \ gproxy.c \ gproxyaddress.c \ gproxyaddressenumerator.c \ - gproxyconnection.c \ - gproxyconnection.h \ gsocketservice.c \ gsrvtarget.c \ gtcpconnection.c \ + gtcpwrapperconnection.c \ gthreadedsocketservice.c\ gthemedicon.c \ gthreadedresolver.c \ @@ -528,6 +527,7 @@ gio_headers = \ gsocketservice.h \ gsrvtarget.h \ gtcpconnection.h \ + gtcpwrapperconnection.h \ gthreadedsocketservice.h\ gthemedicon.h \ gvfs.h \ diff --git a/gio/gio.h b/gio/gio.h index 0babc7c10..714e935d3 100644 --- a/gio/gio.h +++ b/gio/gio.h @@ -117,6 +117,7 @@ #include #include #include +#include #include #include #include diff --git a/gio/gio.symbols b/gio/gio.symbols index 867cf6385..d3e8379a1 100644 --- a/gio/gio.symbols +++ b/gio/gio.symbols @@ -1994,3 +1994,11 @@ g_pollable_output_stream_is_writable g_pollable_output_stream_write_nonblocking #endif #endif + +#if IN_HEADER(__G_TCP_WRAPPER_CONNECTION_H__) +#if IN_FILE(__G_TCP_WRAPPER_CONNECTION_C__) +g_tcp_wrapper_connection_get_type G_GNUC_CONST +g_tcp_wrapper_connection_get_base_io_stream +g_tcp_wrapper_connection_new +#endif +#endif diff --git a/gio/giotypes.h b/gio/giotypes.h index 808e84d41..fef1218bf 100644 --- a/gio/giotypes.h +++ b/gio/giotypes.h @@ -191,6 +191,7 @@ typedef struct _GSrvTarget GSrvTarget; * Since: 2.22 **/ typedef struct _GTcpConnection GTcpConnection; +typedef struct _GTcpWrapperConnection GTcpWrapperConnection; /** * GThreadedSocketService: * diff --git a/gio/gproxyconnection.c b/gio/gproxyconnection.c deleted file mode 100644 index 2e909af7d..000000000 --- a/gio/gproxyconnection.c +++ /dev/null @@ -1,155 +0,0 @@ -/* GIO - GLib Input, Output and Streaming Library - * - * Copyright © 2010 Collabora Ltd. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General - * Public License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Nicolas Dufresne - */ - -#include "config.h" - -#include "gproxyconnection.h" - -#include "gtcpconnection.h" -#include "glibintl.h" - -#define g_proxy_connection_get_type _g_proxy_connection_get_type -G_DEFINE_TYPE (GProxyConnection, - g_proxy_connection, G_TYPE_TCP_CONNECTION); - -enum -{ - PROP_NONE, - PROP_IO_STREAM -}; - -struct _GProxyConnectionPrivate -{ - GIOStream *io_stream; -}; - -static GInputStream * -g_proxy_connection_get_input_stream (GIOStream *io_stream) -{ - GProxyConnection *connection; - connection = G_PROXY_PROXY_CONNECTION (io_stream); - return g_io_stream_get_input_stream (connection->priv->io_stream); -} - -static GOutputStream * -g_proxy_connection_get_output_stream (GIOStream *io_stream) -{ - GProxyConnection *connection; - connection = G_PROXY_PROXY_CONNECTION (io_stream); - return g_io_stream_get_output_stream (connection->priv->io_stream); -} - -static void -g_proxy_connection_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - GProxyConnection *connection = G_PROXY_PROXY_CONNECTION (object); - - switch (prop_id) - { - case PROP_IO_STREAM: - g_value_set_object (value, connection->priv->io_stream); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -g_proxy_connection_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - GProxyConnection *connection = G_PROXY_PROXY_CONNECTION (object); - - switch (prop_id) - { - case PROP_IO_STREAM: - connection->priv->io_stream = G_IO_STREAM (g_value_dup_object (value)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -g_proxy_connection_finalize (GObject *object) -{ - GProxyConnection *connection = G_PROXY_PROXY_CONNECTION (object); - - g_object_unref (connection->priv->io_stream); - - G_OBJECT_CLASS (g_proxy_connection_parent_class)->finalize (object); -} - -static void -g_proxy_connection_class_init (GProxyConnectionClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GIOStreamClass *stream_class = G_IO_STREAM_CLASS (klass); - - g_type_class_add_private (klass, sizeof (GProxyConnectionPrivate)); - - gobject_class->set_property = g_proxy_connection_set_property; - gobject_class->get_property = g_proxy_connection_get_property; - gobject_class->finalize = g_proxy_connection_finalize; - - stream_class->get_input_stream = g_proxy_connection_get_input_stream; - stream_class->get_output_stream = g_proxy_connection_get_output_stream; - - g_object_class_install_property (gobject_class, - PROP_IO_STREAM, - g_param_spec_object ("io-stream", - P_("IO Stream"), - P_("The altered streams"), - G_TYPE_SOCKET_CONNECTION, - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); -} - -static void -g_proxy_connection_init (GProxyConnection *connection) -{ - connection->priv = G_TYPE_INSTANCE_GET_PRIVATE (connection, - G_TYPE_PROXY_CONNECTION, - GProxyConnectionPrivate); -} - -GSocketConnection * -_g_proxy_connection_new (GTcpConnection *connection, - GIOStream *io_stream) -{ - GSocket *socket; - - socket = g_socket_connection_get_socket (G_SOCKET_CONNECTION (connection)); - - return G_SOCKET_CONNECTION (g_object_new (G_TYPE_PROXY_CONNECTION, - "io-stream", io_stream, - "socket", socket, - NULL)); -} diff --git a/gio/gproxyconnection.h b/gio/gproxyconnection.h deleted file mode 100644 index 901a29037..000000000 --- a/gio/gproxyconnection.h +++ /dev/null @@ -1,69 +0,0 @@ -/* GIO - GLib Input, Output and Streaming Library - * Copyright © 2010 Collabora Ltd. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation; either version 2 of the licence or (at - * your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General - * Public License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - * - * Authors: Nicolas Dufresne - * - */ - -#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION) -#error "Only can be included directly." -#endif - -#ifndef __G_PROXY_PROXY_CONNECTION_H__ -#define __G_PROXY_PROXY_CONNECTION_H__ - -#include -#include - -G_BEGIN_DECLS - -#define G_TYPE_PROXY_CONNECTION (_g_proxy_connection_get_type ()) -#define G_PROXY_PROXY_CONNECTION(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \ - G_TYPE_PROXY_CONNECTION, GProxyConnection)) -#define G_PROXY_PROXY_CONNECTION_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), \ - G_TYPE_PROXY_CONNECTION, GProxyConnectionClass)) -#define G_IS_PROXY_CONNECTION(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \ - G_TYPE_PROXY_CONNECTION)) -#define G_IS_PROXY_CONNECTION_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), \ - G_TYPE_PROXY_CONNECTION)) -#define G_PROXY_PROXY_CONNECTION_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), \ - G_TYPE_PROXY_CONNECTION, GProxyConnectionClass)) - -typedef struct _GProxyConnection GProxyConnection; -typedef struct _GProxyConnectionPrivate GProxyConnectionPrivate; -typedef struct _GProxyConnectionClass GProxyConnectionClass; - -struct _GProxyConnectionClass -{ - GTcpConnectionClass parent_class; -}; - -struct _GProxyConnection -{ - GTcpConnection parent_instance; - GProxyConnectionPrivate *priv; -}; - -GType _g_proxy_connection_get_type (void) G_GNUC_CONST; - -GSocketConnection *_g_proxy_connection_new (GTcpConnection *connection, - GIOStream *io_stream); - -G_END_DECLS - -#endif /* __G_PROXY_PROXY_CONNECTION_H__ */ diff --git a/gio/gsocketclient.c b/gio/gsocketclient.c index 982dedc89..30e677abe 100644 --- a/gio/gsocketclient.c +++ b/gio/gsocketclient.c @@ -34,16 +34,17 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include #include #include +#include #include "glibintl.h" @@ -679,14 +680,15 @@ g_socket_client_connect (GSocketClient *client, g_clear_error (&last_error); socket = create_socket (client, address, &last_error); - if (socket != NULL) + if (socket == NULL) { - if (g_socket_connect (socket, address, cancellable, &last_error)) - connection = g_socket_connection_factory_create_connection (socket); - - g_object_unref (socket); + g_object_unref (address); + continue; } + if (g_socket_connect (socket, address, cancellable, &last_error)) + connection = g_socket_connection_factory_create_connection (socket); + if (connection && G_IS_PROXY_ADDRESS (address) && client->priv->enable_proxy) @@ -716,31 +718,30 @@ g_socket_client_connect (GSocketClient *client, else if (proxy) { GIOStream *io_stream; - GTcpConnection *old_connection = G_TCP_CONNECTION (connection); io_stream = g_proxy_connect (proxy, - G_IO_STREAM (old_connection), + G_IO_STREAM (connection), proxy_addr, cancellable, &last_error); + g_object_unref (connection); + g_object_unref (proxy); if (io_stream) { if (G_IS_SOCKET_CONNECTION (io_stream)) - connection = G_SOCKET_CONNECTION (g_object_ref (io_stream)); + connection = G_SOCKET_CONNECTION (io_stream); else - connection = _g_proxy_connection_new (old_connection, - io_stream); - - g_object_unref (io_stream); + { + connection = g_tcp_wrapper_connection_new (G_POLLABLE_IO_STREAM (io_stream), + socket); + g_object_unref (io_stream); + } } else { connection = NULL; } - - g_object_unref (old_connection); - g_object_unref (proxy); } else if (!g_hash_table_lookup_extended (client->priv->app_proxies, protocol, NULL, NULL)) @@ -753,6 +754,7 @@ g_socket_client_connect (GSocketClient *client, } } + g_object_unref (socket); g_object_unref (address); } g_object_unref (enumerator); @@ -991,28 +993,30 @@ g_socket_client_proxy_connect_callback (GObject *object, { GSocketClientAsyncConnectData *data = user_data; GIOStream *io_stream; - GTcpConnection *old_connection = G_TCP_CONNECTION (data->connection); io_stream = g_proxy_connect_finish (G_PROXY (object), result, &data->last_error); + g_object_unref (data->connection); if (io_stream) { if (G_IS_SOCKET_CONNECTION (io_stream)) - data->connection = G_SOCKET_CONNECTION (g_object_ref (io_stream)); + data->connection = G_SOCKET_CONNECTION (io_stream); else - data->connection = _g_proxy_connection_new (old_connection, - io_stream); - g_object_unref (io_stream); + { + data->connection = g_tcp_wrapper_connection_new (G_POLLABLE_IO_STREAM (io_stream), + data->current_socket); + g_object_unref (io_stream); + } } else { data->connection = NULL; + g_object_unref (data->current_socket); + data->current_socket = NULL; } - g_object_unref (old_connection); - g_socket_client_async_connect_complete (data); } @@ -1038,6 +1042,8 @@ g_socket_client_proxy_connect (GSocketClientAsyncConnectData *data) g_object_unref (data->connection); data->connection = NULL; + g_object_unref (data->current_socket); + data->current_socket = NULL; enumerator_next_async (data); } @@ -1062,6 +1068,8 @@ g_socket_client_proxy_connect (GSocketClientAsyncConnectData *data) g_object_unref (data->connection); data->connection = NULL; + g_object_unref (data->current_socket); + data->current_socket = NULL; enumerator_next_async (data); } @@ -1074,8 +1082,6 @@ g_socket_client_socket_connected (GSocketClientAsyncConnectData *data) data->connection = g_socket_connection_factory_create_connection (data->current_socket); - g_object_unref (data->current_socket); - data->current_socket = NULL; if (data->proxy_addr) g_socket_client_proxy_connect (data); diff --git a/gio/gtcpwrapperconnection.c b/gio/gtcpwrapperconnection.c new file mode 100644 index 000000000..47970ad97 --- /dev/null +++ b/gio/gtcpwrapperconnection.c @@ -0,0 +1,200 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright © 2010 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Nicolas Dufresne + */ + +/** + * SECTION: gtcpwrapperconnection + * @title: GTcpWrapperConnection + * @short_description: a wrapper for non-#GSocketConnection-based + * #GIOStreams that are nonetheless based on a #GSocket + * @see_also: #GSocketConnection. + * + * A #GTcpWrapperConnection can be used to wrap a #GIOStream that is + * based on a #GSocket, but which is not actually a + * #GSocketConnection. This is used by #GSocketClient so that it can + * always return a #GSocketConnection, even when the connection it has + * actually created is not directly a #GSocketConnection. + * + * Since: 2.28 + */ + +#include "config.h" + +#include "gtcpwrapperconnection.h" + +#include "gtcpconnection.h" +#include "glibintl.h" + +G_DEFINE_TYPE (GTcpWrapperConnection, + g_tcp_wrapper_connection, G_TYPE_TCP_CONNECTION); + +enum +{ + PROP_NONE, + PROP_BASE_IO_STREAM +}; + +struct _GTcpWrapperConnectionPrivate +{ + GIOStream *base_io_stream; +}; + +static GInputStream * +g_tcp_wrapper_connection_get_input_stream (GIOStream *io_stream) +{ + GTcpWrapperConnection *connection = G_TCP_WRAPPER_CONNECTION (io_stream); + + return g_io_stream_get_input_stream (connection->priv->base_io_stream); +} + +static GOutputStream * +g_tcp_wrapper_connection_get_output_stream (GIOStream *io_stream) +{ + GTcpWrapperConnection *connection = G_TCP_WRAPPER_CONNECTION (io_stream); + + return g_io_stream_get_output_stream (connection->priv->base_io_stream); +} + +static void +g_tcp_wrapper_connection_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GTcpWrapperConnection *connection = G_TCP_WRAPPER_CONNECTION (object); + + switch (prop_id) + { + case PROP_BASE_IO_STREAM: + g_value_set_object (value, connection->priv->base_io_stream); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +g_tcp_wrapper_connection_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GTcpWrapperConnection *connection = G_TCP_WRAPPER_CONNECTION (object); + + switch (prop_id) + { + case PROP_BASE_IO_STREAM: + connection->priv->base_io_stream = g_value_dup_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +g_tcp_wrapper_connection_finalize (GObject *object) +{ + GTcpWrapperConnection *connection = G_TCP_WRAPPER_CONNECTION (object); + + if (connection->priv->base_io_stream) + g_object_unref (connection->priv->base_io_stream); + + G_OBJECT_CLASS (g_tcp_wrapper_connection_parent_class)->finalize (object); +} + +static void +g_tcp_wrapper_connection_class_init (GTcpWrapperConnectionClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GIOStreamClass *stream_class = G_IO_STREAM_CLASS (klass); + + g_type_class_add_private (klass, sizeof (GTcpWrapperConnectionPrivate)); + + gobject_class->set_property = g_tcp_wrapper_connection_set_property; + gobject_class->get_property = g_tcp_wrapper_connection_get_property; + gobject_class->finalize = g_tcp_wrapper_connection_finalize; + + stream_class->get_input_stream = g_tcp_wrapper_connection_get_input_stream; + stream_class->get_output_stream = g_tcp_wrapper_connection_get_output_stream; + + g_object_class_install_property (gobject_class, + PROP_BASE_IO_STREAM, + g_param_spec_object ("base-io-stream", + P_("Base IO Stream"), + P_("The wrapped GIOStream"), + G_TYPE_IO_STREAM, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} + +static void +g_tcp_wrapper_connection_init (GTcpWrapperConnection *connection) +{ + connection->priv = G_TYPE_INSTANCE_GET_PRIVATE (connection, + G_TYPE_TCP_WRAPPER_CONNECTION, + GTcpWrapperConnectionPrivate); +} + +/** + * g_tcp_wrapper_connection_new: + * @base_io_stream: the #GIOStream to wrap + * @socket: the #GSocket associated with @base_io_stream + * + * Wraps @base_io_stream and @socket together as a #GSocketConnection. + * + * Return value: the new #GSocketConnection. + * + * Since: 2.28 + */ +GSocketConnection * +g_tcp_wrapper_connection_new (GIOStream *base_io_stream, + GSocket *socket) +{ + g_return_val_if_fail (G_IS_IO_STREAM (base_io_stream), NULL); + g_return_val_if_fail (G_IS_SOCKET (socket), NULL); + g_return_val_if_fail (g_socket_get_family (socket) == G_SOCKET_FAMILY_IPV4 || + g_socket_get_family (socket) == G_SOCKET_FAMILY_IPV6, NULL); + g_return_val_if_fail (g_socket_get_socket_type (socket) == G_SOCKET_TYPE_STREAM, NULL); + + return g_object_new (G_TYPE_TCP_WRAPPER_CONNECTION, + "base-io-stream", base_io_stream, + "socket", socket, + NULL); +} + +/** + * g_tcp_wrapper_connection_get_base_io_stream: + * @conn: a #GTcpWrapperConnection + * + * Get's @conn's base #GIOStream + * + * Return value: (transfer none): @conn's base #GIOStream + */ +GIOStream * +g_tcp_wrapper_connection_get_base_io_stream (GTcpWrapperConnection *conn) +{ + g_return_val_if_fail (G_IS_TCP_WRAPPER_CONNECTION (conn), NULL); + + return conn->priv->base_io_stream; +} diff --git a/gio/gtcpwrapperconnection.h b/gio/gtcpwrapperconnection.h new file mode 100644 index 000000000..01d3a03a8 --- /dev/null +++ b/gio/gtcpwrapperconnection.h @@ -0,0 +1,68 @@ +/* GIO - GLib Input, Output and Streaming Library + * Copyright © 2010 Collabora Ltd. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2 of the licence or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Nicolas Dufresne + * + */ + +#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __G_TCP_WRAPPER_CONNECTION_H__ +#define __G_TCP_WRAPPER_CONNECTION_H__ + +#include + +G_BEGIN_DECLS + +#define G_TYPE_TCP_WRAPPER_CONNECTION (g_tcp_wrapper_connection_get_type ()) +#define G_TCP_WRAPPER_CONNECTION(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \ + G_TYPE_TCP_WRAPPER_CONNECTION, GTcpWrapperConnection)) +#define G_TCP_WRAPPER_CONNECTION_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), \ + G_TYPE_TCP_WRAPPER_CONNECTION, GTcpWrapperConnectionClass)) +#define G_IS_TCP_WRAPPER_CONNECTION(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \ + G_TYPE_TCP_WRAPPER_CONNECTION)) +#define G_IS_TCP_WRAPPER_CONNECTION_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), \ + G_TYPE_TCP_WRAPPER_CONNECTION)) +#define G_TCP_WRAPPER_CONNECTION_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), \ + G_TYPE_TCP_WRAPPER_CONNECTION, GTcpWrapperConnectionClass)) + +typedef struct _GTcpWrapperConnectionPrivate GTcpWrapperConnectionPrivate; +typedef struct _GTcpWrapperConnectionClass GTcpWrapperConnectionClass; + +struct _GTcpWrapperConnectionClass +{ + GTcpConnectionClass parent_class; +}; + +struct _GTcpWrapperConnection +{ + GTcpConnection parent_instance; + GTcpWrapperConnectionPrivate *priv; +}; + +GType g_tcp_wrapper_connection_get_type (void) G_GNUC_CONST; + +GSocketConnection *g_tcp_wrapper_connection_new (GIOStream *base_io_stream, + GSocket *socket); +GIOStream *g_tcp_wrapper_connection_get_base_io_stream (GTcpWrapperConnection *conn); + +G_END_DECLS + +#endif /* __G_TCP_WRAPPER_CONNECTION_H__ */ From 59d62726de8efdd478ca1c940134df1112a006f2 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Mon, 21 Dec 2009 20:50:32 +0100 Subject: [PATCH 17/44] Add initial TLS (SSL) support to gio This adds an extension point for TLS connections to gio, with a gnutls-based implementation in glib-networking. Full TLS support is still a work in progress; the current API is missing some features, and parts of it may still be changed before 2.28. https://bugzilla.gnome.org/show_bug.cgi?id=588189 --- docs/reference/gio/gio-docs.xml | 9 + docs/reference/gio/gio-sections.txt | 129 ++++- docs/reference/gio/gio.types | 5 + gio/Makefile.am | 13 +- gio/gdummytlsbackend.c | 274 +++++++++++ gio/gdummytlsbackend.h | 46 ++ gio/gio-marshal.list | 2 + gio/gio.h | 5 + gio/gio.symbols | 77 ++- gio/gioenums.h | 100 ++++ gio/giomodule.c | 6 + gio/giotypes.h | 8 + gio/gsocketclient.c | 312 ++++++++++-- gio/gsocketclient.h | 7 + gio/gtlsbackend.c | 201 ++++++++ gio/gtlsbackend.h | 92 ++++ gio/gtlscertificate.c | 486 +++++++++++++++++++ gio/gtlscertificate.h | 75 +++ gio/gtlsclientconnection.c | 333 +++++++++++++ gio/gtlsclientconnection.h | 72 +++ gio/gtlsconnection.c | 720 ++++++++++++++++++++++++++++ gio/gtlsconnection.h | 137 ++++++ gio/gtlsserverconnection.c | 96 ++++ gio/gtlsserverconnection.h | 61 +++ gio/tests/socket-client.c | 193 +++++--- gio/tests/socket-common.c | 61 +++ gio/tests/socket-server.c | 164 ++++--- 27 files changed, 3473 insertions(+), 211 deletions(-) create mode 100644 gio/gdummytlsbackend.c create mode 100644 gio/gdummytlsbackend.h create mode 100644 gio/gtlsbackend.c create mode 100644 gio/gtlsbackend.h create mode 100644 gio/gtlscertificate.c create mode 100644 gio/gtlscertificate.h create mode 100644 gio/gtlsclientconnection.c create mode 100644 gio/gtlsclientconnection.h create mode 100644 gio/gtlsconnection.c create mode 100644 gio/gtlsconnection.h create mode 100644 gio/gtlsserverconnection.c create mode 100644 gio/gtlsserverconnection.h diff --git a/docs/reference/gio/gio-docs.xml b/docs/reference/gio/gio-docs.xml index 850a58af4..4676bc02a 100644 --- a/docs/reference/gio/gio-docs.xml +++ b/docs/reference/gio/gio-docs.xml @@ -125,6 +125,15 @@ + + TLS (SSL) support + + + + + + + DNS resolution diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt index d6f5aedb2..3574e1ead 100644 --- a/docs/reference/gio/gio-sections.txt +++ b/docs/reference/gio/gio-sections.txt @@ -1798,13 +1798,17 @@ g_socket_client_set_local_address g_socket_client_set_protocol g_socket_client_set_socket_type g_socket_client_set_timeout +g_socket_client_set_enable_proxy +g_socket_client_set_tls +g_socket_client_set_tls_validation_flags g_socket_client_get_family g_socket_client_get_local_address g_socket_client_get_protocol g_socket_client_get_socket_type g_socket_client_get_timeout g_socket_client_get_enable_proxy -g_socket_client_set_enable_proxy +g_socket_client_get_tls +g_socket_client_get_tls_validation_flags GSocketClientClass G_IS_SOCKET_CLIENT @@ -2994,3 +2998,126 @@ G_TYPE_POLLABLE_OUTPUT_STREAM g_pollable_output_stream_get_type
+ +
+gtls +G_TLS_ERROR +GTlsError + +GTlsAuthenticationMode +GTlsCertificateFlags +
+ +
+gtlsbackend +GTlsBackend</FILE> +G_TLS_BACKEND_EXTENSION_POINT_NAME +GTlsBackend +GTlsBackendInterface +g_tls_backend_get_default +g_tls_backend_supports_tls +g_tls_backend_get_certificate_type +g_tls_backend_get_client_connection_type +g_tls_backend_get_server_connection_type +<SUBSECTION Standard> +G_IS_TLS_BACKEND +G_TLS_BACKEND +G_TLS_BACKEND_GET_INTERFACE +G_TYPE_TLS_BACKEND +g_tls_error_quark +<SUBSECTION Private> +g_tls_backend_get_type +</SECTION> + +<SECTION> +<FILE>gtlscertificate</FILE> +<TITLE>GTlsCertificate +GTlsCertificate +g_tls_certificate_new +g_tls_certificate_new_from_pem +g_tls_certificate_new_from_file +g_tls_certificate_new_from_files +g_tls_certificate_list_new_from_file +g_tls_certificate_get_issuer + +GTlsCertificateClass +GTlsCertificatePrivate +G_IS_TLS_CERTIFICATE +G_IS_TLS_CERTIFICATE_CLASS +G_TLS_CERTIFICATE +G_TLS_CERTIFICATE_CLASS +G_TLS_CERTIFICATE_GET_CLASS +G_TYPE_TLS_CERTIFICATE + +g_tls_certificate_get_type +
+ +
+gtlsconnection +GTlsConnection +GTlsConnection +g_tls_connection_set_certificate +g_tls_connection_get_certificate +g_tls_connection_get_peer_certificate +g_tls_connection_set_require_close_notify +g_tls_connection_get_require_close_notify +GTlsRehandshakeMode +g_tls_connection_set_rehandshake_mode +g_tls_connection_get_rehandshake_mode + +g_tls_connection_handshake +g_tls_connection_handshake_async +g_tls_connection_handshake_finish + +g_tls_connection_set_peer_certificate +g_tls_connection_emit_accept_certificate +g_tls_connection_emit_need_certificate + +GTlsConnectionClass +GTlsConnectionPrivate +G_IS_TLS_CONNECTION +G_IS_TLS_CONNECTION_CLASS +G_TLS_CONNECTION +G_TLS_CONNECTION_CLASS +G_TLS_CONNECTION_GET_CLASS +G_TYPE_TLS_CONNECTION + +g_tls_connection_get_type +
+ +
+gtlsclientconnection +GTlsClientConnection +GTlsClientConnection +GTlsClientConnectionInterface +g_tls_client_connection_new +g_tls_client_connection_set_server_identity +g_tls_client_connection_get_server_identity +g_tls_client_connection_set_validation_flags +g_tls_client_connection_get_validation_flags +g_tls_client_connection_set_use_ssl3 +g_tls_client_connection_get_use_ssl3 +g_tls_client_connection_get_accepted_cas + +G_IS_TLS_CLIENT_CONNECTION +G_TLS_CLIENT_CONNECTION +G_TLS_CLIENT_CONNECTION_GET_INTERFACE +G_TYPE_TLS_CLIENT_CONNECTION + +g_tls_client_connection_get_type +
+ +
+gtlsserverconnection +GTlsServerConnection +GTlsServerConnection +GTlsServerConnectionInterface +g_tls_server_connection_new + +G_IS_TLS_SERVER_CONNECTION +G_TLS_SERVER_CONNECTION +G_TLS_SERVER_CONNECTION_GET_INTERFACE +G_TYPE_TLS_SERVER_CONNECTION + +g_tls_server_connection_get_type +
diff --git a/docs/reference/gio/gio.types b/docs/reference/gio/gio.types index 44361788c..4b3afe0e7 100644 --- a/docs/reference/gio/gio.types +++ b/docs/reference/gio/gio.types @@ -108,6 +108,11 @@ g_tcp_connection_get_type g_tcp_wrapper_connection_get_type g_themed_icon_get_type g_threaded_socket_service_get_type +g_tls_backend_get_type +g_tls_certificate_get_type +g_tls_client_connection_get_type +g_tls_connection_get_type +g_tls_server_connection_get_type g_unix_connection_get_type g_unix_fd_list_get_type g_unix_fd_message_get_type diff --git a/gio/Makefile.am b/gio/Makefile.am index b70583a94..89aa16276 100644 --- a/gio/Makefile.am +++ b/gio/Makefile.am @@ -202,7 +202,6 @@ platform_libadd += win32/libgiowin32.la platform_deps += win32/libgiowin32.la endif - SUBDIRS += . if HAVE_FAM @@ -307,6 +306,8 @@ libgio_2_0_la_SOURCES = \ gdummyfile.c \ gdummyproxyresolver.c \ gdummyproxyresolver.h \ + gdummytlsbackend.c \ + gdummytlsbackend.h \ gemblem.h \ gemblem.c \ gemblemedicon.h \ @@ -381,6 +382,11 @@ libgio_2_0_la_SOURCES = \ gthemedicon.c \ gthreadedresolver.c \ gthreadedresolver.h \ + gtlsbackend.c \ + gtlscertificate.c \ + gtlsclientconnection.c \ + gtlsconnection.c \ + gtlsserverconnection.c \ gunionvolumemonitor.c \ gunionvolumemonitor.h \ gvfs.c \ @@ -530,6 +536,11 @@ gio_headers = \ gtcpwrapperconnection.h \ gthreadedsocketservice.h\ gthemedicon.h \ + gtlsbackend.h \ + gtlscertificate.h \ + gtlsclientconnection.h \ + gtlsconnection.h \ + gtlsserverconnection.h \ gvfs.h \ gvolume.h \ gvolumemonitor.h \ diff --git a/gio/gdummytlsbackend.c b/gio/gdummytlsbackend.c new file mode 100644 index 000000000..fd55aa9e5 --- /dev/null +++ b/gio/gdummytlsbackend.c @@ -0,0 +1,274 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "gdummytlsbackend.h" + +#include + +#include "gasyncresult.h" +#include "gcancellable.h" +#include "ginitable.h" +#include "gtlsbackend.h" +#include "gtlscertificate.h" +#include "gtlsclientconnection.h" +#include "gtlsserverconnection.h" +#include "gsimpleasyncresult.h" + +#include "giomodule.h" +#include "giomodule-priv.h" + +#include "glibintl.h" + +static GType _g_dummy_tls_certificate_get_type (void); +static GType _g_dummy_tls_connection_get_type (void); + +struct _GDummyTlsBackend { + GObject parent_instance; +}; + +static void g_dummy_tls_backend_iface_init (GTlsBackendInterface *iface); + +#define g_dummy_tls_backend_get_type _g_dummy_tls_backend_get_type +G_DEFINE_TYPE_WITH_CODE (GDummyTlsBackend, g_dummy_tls_backend, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_TLS_BACKEND, + g_dummy_tls_backend_iface_init) + _g_io_modules_ensure_extension_points_registered (); + g_io_extension_point_implement (G_TLS_BACKEND_EXTENSION_POINT_NAME, + g_define_type_id, + "dummy", + -100)) + +static void +g_dummy_tls_backend_init (GDummyTlsBackend *backend) +{ +} + +static void +g_dummy_tls_backend_class_init (GDummyTlsBackendClass *backend_class) +{ +} + +static void +g_dummy_tls_backend_iface_init (GTlsBackendInterface *iface) +{ + iface->get_certificate_type = _g_dummy_tls_certificate_get_type; + iface->get_client_connection_type = _g_dummy_tls_connection_get_type; + iface->get_server_connection_type = _g_dummy_tls_connection_get_type; +} + +/* Dummy certificate type */ + +typedef struct _GDummyTlsCertificate GDummyTlsCertificate; +typedef struct _GDummyTlsCertificateClass GDummyTlsCertificateClass; + +struct _GDummyTlsCertificate { + GTlsCertificate parent_instance; +}; + +struct _GDummyTlsCertificateClass { + GTlsCertificateClass parent_class; +}; + +enum +{ + PROP_CERTIFICATE_0, + + PROP_CERTIFICATE, + PROP_CERTIFICATE_PEM, + PROP_PRIVATE_KEY, + PROP_PRIVATE_KEY_PEM +}; + +static void g_dummy_tls_certificate_initable_iface_init (GInitableIface *iface); + +#define g_dummy_tls_certificate_get_type _g_dummy_tls_certificate_get_type +G_DEFINE_TYPE_WITH_CODE (GDummyTlsCertificate, g_dummy_tls_certificate, G_TYPE_TLS_CERTIFICATE, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, + g_dummy_tls_certificate_initable_iface_init);) + +static void +g_dummy_tls_certificate_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + /* We need to define this method to make GObject happy, but it will + * never be possible to construct a working GDummyTlsCertificate, so + * it doesn't have to do anything useful. + */ +} + +static void +g_dummy_tls_certificate_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + /* Just ignore all attempts to set properties. */ +} + +static void +g_dummy_tls_certificate_class_init (GDummyTlsCertificateClass *certificate_class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (certificate_class); + + gobject_class->get_property = g_dummy_tls_certificate_get_property; + gobject_class->set_property = g_dummy_tls_certificate_set_property; + + g_object_class_override_property (gobject_class, PROP_CERTIFICATE, "certificate"); + g_object_class_override_property (gobject_class, PROP_CERTIFICATE_PEM, "certificate-pem"); + g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY, "private-key"); + g_object_class_override_property (gobject_class, PROP_PRIVATE_KEY_PEM, "private-key-pem"); +} + +static void +g_dummy_tls_certificate_init (GDummyTlsCertificate *certificate) +{ +} + +static gboolean +g_dummy_tls_certificate_initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error) +{ + g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_MISC, + _("TLS support is not available")); + return FALSE; +} + +static void +g_dummy_tls_certificate_initable_iface_init (GInitableIface *iface) +{ + iface->init = g_dummy_tls_certificate_initable_init; +} + +/* Dummy connection type; since GTlsClientConnection and + * GTlsServerConnection are just interfaces, we can implement them + * both on a single object. + */ + +typedef struct _GDummyTlsConnection GDummyTlsConnection; +typedef struct _GDummyTlsConnectionClass GDummyTlsConnectionClass; + +struct _GDummyTlsConnection { + GTlsConnection parent_instance; +}; + +struct _GDummyTlsConnectionClass { + GTlsConnectionClass parent_class; +}; + +enum +{ + PROP_CONNECTION_0, + + PROP_BASE_IO_STREAM, + PROP_REQUIRE_CLOSE_NOTIFY, + PROP_REHANDSHAKE_MODE, + PROP_VALIDATION_FLAGS, + PROP_SERVER_IDENTITY, + PROP_USE_SSL3, + PROP_ACCEPTED_CAS, + PROP_AUTHENTICATION_MODE +}; + +static void g_dummy_tls_connection_initable_iface_init (GInitableIface *iface); + +#define g_dummy_tls_connection_get_type _g_dummy_tls_connection_get_type +G_DEFINE_TYPE_WITH_CODE (GDummyTlsConnection, g_dummy_tls_connection, G_TYPE_TLS_CONNECTION, + G_IMPLEMENT_INTERFACE (G_TYPE_TLS_CLIENT_CONNECTION, NULL); + G_IMPLEMENT_INTERFACE (G_TYPE_TLS_SERVER_CONNECTION, NULL); + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, + g_dummy_tls_connection_initable_iface_init);) + +static void +g_dummy_tls_connection_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ +} + +static void +g_dummy_tls_connection_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ +} + +static gboolean +g_dummy_tls_connection_close (GIOStream *stream, + GCancellable *cancellable, + GError **error) +{ + return TRUE; +} + +static void +g_dummy_tls_connection_class_init (GDummyTlsConnectionClass *connection_class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (connection_class); + GIOStreamClass *io_stream_class = G_IO_STREAM_CLASS (connection_class); + + gobject_class->get_property = g_dummy_tls_connection_get_property; + gobject_class->set_property = g_dummy_tls_connection_set_property; + + /* Need to override this because when initable_init fails it will + * dispose the connection, which will close it, which would + * otherwise try to close its input/output streams, which don't + * exist. + */ + io_stream_class->close_fn = g_dummy_tls_connection_close; + + g_object_class_override_property (gobject_class, PROP_BASE_IO_STREAM, "base-io-stream"); + g_object_class_override_property (gobject_class, PROP_REQUIRE_CLOSE_NOTIFY, "require-close-notify"); + g_object_class_override_property (gobject_class, PROP_REHANDSHAKE_MODE, "rehandshake-mode"); + g_object_class_override_property (gobject_class, PROP_VALIDATION_FLAGS, "validation-flags"); + g_object_class_override_property (gobject_class, PROP_SERVER_IDENTITY, "server-identity"); + g_object_class_override_property (gobject_class, PROP_USE_SSL3, "use-ssl3"); + g_object_class_override_property (gobject_class, PROP_ACCEPTED_CAS, "accepted-cas"); + g_object_class_override_property (gobject_class, PROP_AUTHENTICATION_MODE, "authentication-mode"); + +} + +static void +g_dummy_tls_connection_init (GDummyTlsConnection *connection) +{ +} + +static gboolean +g_dummy_tls_connection_initable_init (GInitable *initable, + GCancellable *cancellable, + GError **error) +{ + g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_MISC, + _("TLS support is not available")); + return FALSE; +} + +static void +g_dummy_tls_connection_initable_iface_init (GInitableIface *iface) +{ + iface->init = g_dummy_tls_connection_initable_init; +} + diff --git a/gio/gdummytlsbackend.h b/gio/gdummytlsbackend.h new file mode 100644 index 000000000..40b5038b8 --- /dev/null +++ b/gio/gdummytlsbackend.h @@ -0,0 +1,46 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __G_DUMMY_TLS_BACKEND_H__ +#define __G_DUMMY_TLS_BACKEND_H__ + +#include + +G_BEGIN_DECLS + +#define G_TYPE_DUMMY_TLS_BACKEND (_g_dummy_tls_backend_get_type ()) +#define G_DUMMY_TLS_BACKEND(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DUMMY_TLS_BACKEND, GDummyTlsBackend)) +#define G_DUMMY_TLS_BACKEND_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_DUMMY_TLS_BACKEND, GDummyTlsBackendClass)) +#define G_IS_DUMMY_TLS_BACKEND(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DUMMY_TLS_BACKEND)) +#define G_IS_DUMMY_TLS_BACKEND_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_DUMMY_TLS_BACKEND)) +#define G_DUMMY_TLS_BACKEND_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_DUMMY_TLS_BACKEND, GDummyTlsBackendClass)) + +typedef struct _GDummyTlsBackend GDummyTlsBackend; +typedef struct _GDummyTlsBackendClass GDummyTlsBackendClass; + +struct _GDummyTlsBackendClass { + GObjectClass parent_class; +}; + +GType _g_dummy_tls_backend_get_type (void); + +G_END_DECLS + +#endif /* __G_DUMMY_TLS_BACKEND_H__ */ diff --git a/gio/gio-marshal.list b/gio/gio-marshal.list index 00d16a9f7..8a42ad75b 100644 --- a/gio/gio-marshal.list +++ b/gio/gio-marshal.list @@ -27,3 +27,5 @@ INT:OBJECT VOID:INT64 VOID:UINT64 BOOLEAN:FLAGS +BOOLEAN:OBJECT,FLAGS +OBJECT:VOID diff --git a/gio/gio.h b/gio/gio.h index 714e935d3..306012f43 100644 --- a/gio/gio.h +++ b/gio/gio.h @@ -120,6 +120,11 @@ #include #include #include +#include +#include +#include +#include +#include #include #include #include diff --git a/gio/gio.symbols b/gio/gio.symbols index d3e8379a1..c713d1370 100644 --- a/gio/gio.symbols +++ b/gio/gio.symbols @@ -1067,6 +1067,9 @@ g_dbus_signal_flags_get_type G_GNUC_CONST g_dbus_send_message_flags_get_type G_GNUC_CONST g_credentials_type_get_type G_GNUC_CONST g_dbus_message_byte_order_get_type G_GNUC_CONST +g_tls_authentication_mode_get_type G_GNUC_CONST +g_tls_certificate_flags_get_type G_GNUC_CONST +g_tls_rehandshake_mode_get_type G_GNUC_CONST #endif #endif @@ -1371,6 +1374,7 @@ g_socket_control_message_serialize #if IN_HEADER(__G_SOCKET_CLIENT_H__) #if IN_FILE(__G_SOCKET_CLIENT_C__) g_socket_client_get_type G_GNUC_CONST +g_socket_client_add_application_proxy g_socket_client_connect g_socket_client_connect_async g_socket_client_connect_finish @@ -1383,20 +1387,23 @@ g_socket_client_connect_to_service_finish g_socket_client_connect_to_uri g_socket_client_connect_to_uri_async g_socket_client_connect_to_uri_finish +g_socket_client_get_enable_proxy g_socket_client_get_family g_socket_client_get_local_address g_socket_client_get_protocol g_socket_client_get_socket_type g_socket_client_get_timeout -g_socket_client_get_enable_proxy +g_socket_client_get_tls +g_socket_client_get_tls_validation_flags g_socket_client_new +g_socket_client_set_enable_proxy g_socket_client_set_family g_socket_client_set_local_address g_socket_client_set_protocol g_socket_client_set_socket_type g_socket_client_set_timeout -g_socket_client_set_enable_proxy -g_socket_client_add_application_proxy +g_socket_client_set_tls +g_socket_client_set_tls_validation_flags #endif #endif @@ -2002,3 +2009,67 @@ g_tcp_wrapper_connection_get_base_io_stream g_tcp_wrapper_connection_new #endif #endif + +#if IN_HEADER(__G_TLS_BACKEND_H__) +#if IN_FILE(__G_TLS_BACKEND_C__) +g_tls_backend_get_certificate_type +g_tls_backend_get_client_connection_type +g_tls_backend_get_default +g_tls_backend_get_server_connection_type +g_tls_backend_get_type G_GNUC_CONST +g_tls_backend_supports_tls +g_tls_error_get_type G_GNUC_CONST +g_tls_error_quark +#endif +#endif + +#if IN_HEADER(__G_TLS_CERTIFICATE_H__) +#if IN_FILE(__G_TLS_CERTIFICATE_C__) +g_tls_certificate_get_issuer +g_tls_certificate_get_type G_GNUC_CONST +g_tls_certificate_list_new_from_file +g_tls_certificate_new_from_file +g_tls_certificate_new_from_files +g_tls_certificate_new_from_pem +#endif +#endif + +#if IN_HEADER(__G_TLS_CONNECTION_H__) +#if IN_FILE(__G_TLS_CONNECTION_C__) +g_tls_connection_emit_accept_certificate +g_tls_connection_emit_need_certificate +g_tls_connection_get_certificate +g_tls_connection_get_peer_certificate +g_tls_connection_get_rehandshake_mode +g_tls_connection_get_require_close_notify +g_tls_connection_get_type G_GNUC_CONST +g_tls_connection_handshake +g_tls_connection_handshake_async +g_tls_connection_handshake_finish +g_tls_connection_set_certificate +g_tls_connection_set_peer_certificate +g_tls_connection_set_rehandshake_mode +g_tls_connection_set_require_close_notify +#endif +#endif + +#if IN_HEADER(__G_TLS_CLIENT_CONNECTION_H__) +#if IN_FILE(__G_TLS_CLIENT_CONNECTION_C__) +g_tls_client_connection_get_accepted_cas +g_tls_client_connection_get_server_identity +g_tls_client_connection_get_type G_GNUC_CONST +g_tls_client_connection_get_use_ssl3 +g_tls_client_connection_get_validation_flags +g_tls_client_connection_new +g_tls_client_connection_set_server_identity +g_tls_client_connection_set_use_ssl3 +g_tls_client_connection_set_validation_flags +#endif +#endif + +#if IN_HEADER(__G_TLS_SERVER_CONNECTION_H__) +#if IN_FILE(__G_TLS_SERVER_CONNECTION_C__) +g_tls_server_connection_get_type G_GNUC_CONST +g_tls_server_connection_new +#endif +#endif diff --git a/gio/gioenums.h b/gio/gioenums.h index d534eed14..039b5dc50 100644 --- a/gio/gioenums.h +++ b/gio/gioenums.h @@ -1249,6 +1249,106 @@ typedef enum G_APPLICATION_SEND_ENVIRONMENT = (1 << 4) } GApplicationFlags; +/** + * GTlsError: + * @G_TLS_ERROR_MISC: Miscellaneous TLS error + * @G_TLS_ERROR_BAD_CERTIFICATE: A certificate could not be parsed + * @G_TLS_ERROR_NOT_TLS: The TLS handshake failed because the + * peer does not seem to be a TLS server. + * @G_TLS_ERROR_HANDSHAKE: The TLS handshake failed because the + * peer's certificate was not acceptable. + * @G_TLS_ERROR_CERTIFICATE_REQUIRED: The TLS handshake failed because + * the server requested a client-side certificate, but none was + * provided. See #GTlsConnection::need-certificate. + * @G_TLS_ERROR_EOF: The TLS connection was closed without proper + * notice, which may indicate an attack. See + * g_tls_connection_set_require_close_notify(). + * + * An error code used with %G_TLS_ERROR in a #GError returned from a + * TLS-related routine. + * + * Since: 2.28 + */ +typedef enum { + G_TLS_ERROR_MISC, + G_TLS_ERROR_BAD_CERTIFICATE, + G_TLS_ERROR_NOT_TLS, + G_TLS_ERROR_HANDSHAKE, + G_TLS_ERROR_CERTIFICATE_REQUIRED, + G_TLS_ERROR_EOF +} GTlsError; + +/** + * GTlsCertificateFlags: + * @G_TLS_CERTIFICATE_UNKNOWN_CA: The signing certificate authority is + * not known. + * @G_TLS_CERTIFICATE_BAD_IDENTITY: The certificate does not match the + * expected identity of the site that it was retrieved from. + * @G_TLS_CERTIFICATE_NOT_ACTIVATED: The certificate's activation time + * is still in the future + * @G_TLS_CERTIFICATE_EXPIRED: The certificate has expired + * @G_TLS_CERTIFICATE_REVOKED: The certificate has been revoked + * according to the #GTlsContext's certificate revocation list. + * @G_TLS_CERTIFICATE_INSECURE: The certificate's algorithm is + * considered insecure. + * @G_TLS_CERTIFICATE_GENERIC_ERROR: Some other error occurred validating + * the certificate + * @G_TLS_CERTIFICATE_VALIDATE_ALL: the combination of all of the above + * flags + * + * A set of flags describing TLS certification validation. This can be + * used to set which validation steps to perform (eg, with + * g_tls_client_connection_set_validation_flags()), or to describe why + * a particular certificate was rejected (eg, in + * #GTlsConnection::accept-certificate). + * + * Since: 2.28 + */ +typedef enum { + G_TLS_CERTIFICATE_UNKNOWN_CA = (1 << 0), + G_TLS_CERTIFICATE_BAD_IDENTITY = (1 << 1), + G_TLS_CERTIFICATE_NOT_ACTIVATED = (1 << 2), + G_TLS_CERTIFICATE_EXPIRED = (1 << 3), + G_TLS_CERTIFICATE_REVOKED = (1 << 4), + G_TLS_CERTIFICATE_INSECURE = (1 << 5), + G_TLS_CERTIFICATE_GENERIC_ERROR = (1 << 6), + + G_TLS_CERTIFICATE_VALIDATE_ALL = 0x007f +} GTlsCertificateFlags; + +/** + * GTlsAuthenticationMode: + * @G_TLS_AUTHENTICATION_NONE: client authentication not required + * @G_TLS_AUTHENTICATION_REQUESTED: client authentication is requested + * @G_TLS_AUTHENTICATION_REQUIRED: client authentication is required + * + * The client authentication mode for a #GTlsServerConnection. + * + * Since: 2.28 + */ +typedef enum { + G_TLS_AUTHENTICATION_NONE, + G_TLS_AUTHENTICATION_REQUESTED, + G_TLS_AUTHENTICATION_REQUIRED +} GTlsAuthenticationMode; + +/** + * GTlsRehandshakeMode: + * @G_TLS_REHANDSHAKE_NEVER: Never allow rehandshaking + * @G_TLS_REHANDSHAKE_SAFELY: Allow safe rehandshaking only + * @G_TLS_REHANDSHAKE_UNSAFELY: Allow unsafe rehandshaking + * + * When to allow rehandshaking. See + * g_tls_connection_set_rehandshake_mode(). + * + * Since: 2.28 + */ +typedef enum { + G_TLS_REHANDSHAKE_NEVER, + G_TLS_REHANDSHAKE_SAFELY, + G_TLS_REHANDSHAKE_UNSAFELY +} GTlsRehandshakeMode; + G_END_DECLS #endif /* __GIO_ENUMS_H__ */ diff --git a/gio/giomodule.c b/gio/giomodule.c index d1318933f..ecdaab4da 100644 --- a/gio/giomodule.c +++ b/gio/giomodule.c @@ -35,6 +35,7 @@ #include "gsocks4proxy.h" #include "gsocks4aproxy.h" #include "gsocks5proxy.h" +#include "gtlsbackend.h" #include "gvfs.h" #ifdef G_OS_WIN32 #include "gregistrysettingsbackend.h" @@ -480,6 +481,7 @@ extern GType g_win32_directory_monitor_get_type (void); extern GType _g_winhttp_vfs_get_type (void); extern GType _g_dummy_proxy_resolver_get_type (void); +extern GType _g_dummy_tls_backend_get_type (void); #ifdef G_PLATFORM_WIN32 @@ -556,6 +558,9 @@ _g_io_modules_ensure_extension_points_registered (void) ep = g_io_extension_point_register (G_PROXY_EXTENSION_POINT_NAME); g_io_extension_point_set_required_type (ep, G_TYPE_PROXY); + + ep = g_io_extension_point_register (G_TLS_BACKEND_EXTENSION_POINT_NAME); + g_io_extension_point_set_required_type (ep, G_TYPE_TLS_BACKEND); } G_UNLOCK (registered_extensions); @@ -618,6 +623,7 @@ _g_io_modules_ensure_loaded (void) _g_socks4a_proxy_get_type (); _g_socks4_proxy_get_type (); _g_socks5_proxy_get_type (); + _g_dummy_tls_backend_get_type (); } G_UNLOCK (loaded_dirs); diff --git a/gio/giotypes.h b/gio/giotypes.h index fef1218bf..1c350837a 100644 --- a/gio/giotypes.h +++ b/gio/giotypes.h @@ -109,6 +109,7 @@ typedef struct _GIOExtension GIOExtension; * Opaque class for definining and scheduling IO jobs. **/ typedef struct _GIOSchedulerJob GIOSchedulerJob; +typedef struct _GIOStreamAdapter GIOStreamAdapter; typedef struct _GLoadableIcon GLoadableIcon; /* Dummy typedef */ typedef struct _GMemoryInputStream GMemoryInputStream; typedef struct _GMemoryOutputStream GMemoryOutputStream; @@ -202,6 +203,13 @@ typedef struct _GTcpWrapperConnection GTcpWrapperConnectio **/ typedef struct _GThreadedSocketService GThreadedSocketService; typedef struct _GThemedIcon GThemedIcon; +typedef struct _GTlsCertificate GTlsCertificate; +typedef struct _GTlsClientConnection GTlsClientConnection; /* Dummy typedef */ +typedef struct _GTlsClientContext GTlsClientContext; /* Dummy typedef */ +typedef struct _GTlsConnection GTlsConnection; +typedef struct _GTlsContext GTlsContext; +typedef struct _GTlsServerConnection GTlsServerConnection; /* Dummy typedef */ +typedef struct _GTlsServerContext GTlsServerContext; /* Dummy typedef */ typedef struct _GVfs GVfs; /* Dummy typedef */ /** diff --git a/gio/gsocketclient.c b/gio/gsocketclient.c index 30e677abe..046432279 100644 --- a/gio/gsocketclient.c +++ b/gio/gsocketclient.c @@ -40,11 +40,12 @@ #include #include #include -#include #include #include #include #include +#include +#include #include "glibintl.h" @@ -80,6 +81,8 @@ enum PROP_LOCAL_ADDRESS, PROP_TIMEOUT, PROP_ENABLE_PROXY, + PROP_TLS, + PROP_TLS_VALIDATION_FLAGS }; struct _GSocketClientPrivate @@ -91,6 +94,8 @@ struct _GSocketClientPrivate guint timeout; gboolean enable_proxy; GHashTable *app_proxies; + gboolean tls; + GTlsCertificateFlags tls_validation_flags; }; static GSocket * @@ -219,6 +224,14 @@ g_socket_client_get_property (GObject *object, g_value_set_boolean (value, client->priv->enable_proxy); break; + case PROP_TLS: + g_value_set_boolean (value, g_socket_client_get_tls (client)); + break; + + case PROP_TLS_VALIDATION_FLAGS: + g_value_set_flags (value, g_socket_client_get_tls_validation_flags (client)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -258,6 +271,14 @@ g_socket_client_set_property (GObject *object, g_socket_client_set_enable_proxy (client, g_value_get_boolean (value)); break; + case PROP_TLS: + g_socket_client_set_tls (client, g_value_get_boolean (value)); + break; + + case PROP_TLS_VALIDATION_FLAGS: + g_socket_client_set_tls_validation_flags (client, g_value_get_flags (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } @@ -526,6 +547,91 @@ g_socket_client_set_enable_proxy (GSocketClient *client, g_object_notify (G_OBJECT (client), "enable-proxy"); } +/** + * g_socket_client_get_tls: + * @client: a #GSocketClient. + * + * Gets whether @client creates TLS connections. See + * g_socket_client_set_tls() for details. + * + * Returns: whether @client uses TLS + * + * Since: 2.28 + */ +gboolean +g_socket_client_get_tls (GSocketClient *client) +{ + return client->priv->tls; +} + +/** + * g_socket_client_set_tls: + * @client: a #GSocketClient. + * @tls: whether to use TLS + * + * Sets whether @client creates TLS (aka SSL) connections. If @tls is + * %TRUE, @client will wrap its connections in a #GTlsClientConnection + * and perform a TLS handshake when connecting. + * + * Note that since #GSocketClient must return a #GSocketConnection, + * but #GTlsClientConnection is not a #GSocketConnection, this + * actually wraps the resulting #GTlsClientConnection in a + * #GTcpWrapperConnection when returning it. You can use + * g_tcp_wrapper_connection_get_base_io_stream() on the return value + * to extract the #GTlsClientConnection. + * + * Since: 2.28 + */ +void +g_socket_client_set_tls (GSocketClient *client, + gboolean tls) +{ + tls = !!tls; + if (tls == client->priv->tls) + return; + + client->priv->tls = tls; + g_object_notify (G_OBJECT (client), "tls"); +} + +/** + * g_socket_client_get_tls_validation_flags: + * @client: a #GSocketClient. + * + * Gets the TLS validation flags used creating TLS connections via + * @client. + * + * Returns: the TLS validation flags + * + * Since: 2.28 + */ +GTlsCertificateFlags +g_socket_client_get_tls_validation_flags (GSocketClient *client) +{ + return client->priv->tls_validation_flags; +} + +/** + * g_socket_client_set_tls_validation_flags: + * @client: a #GSocketClient. + * @flags: the validation flags + * + * Sets the TLS validation flags used when creating TLS connections + * via @client. The default value is %G_TLS_CERTIFICATE_VALIDATE_ALL. + * + * Since: 2.28 + */ +void +g_socket_client_set_tls_validation_flags (GSocketClient *client, + GTlsCertificateFlags flags) +{ + if (client->priv->tls_validation_flags != flags) + { + client->priv->tls_validation_flags = flags; + g_object_notify (G_OBJECT (client), "tls-validation-flags"); + } +} + static void g_socket_client_class_init (GSocketClientClass *class) { @@ -594,6 +700,23 @@ g_socket_client_class_init (GSocketClientClass *class) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_TLS, + g_param_spec_boolean ("tls", + P_("TLS"), + P_("Whether to create TLS connections"), + FALSE, + G_PARAM_CONSTRUCT | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_TLS_VALIDATION_FLAGS, + g_param_spec_flags ("tls-validation-flags", + P_("TLS validation flags"), + P_("TLS validation flags to use"), + G_TYPE_TLS_CERTIFICATE_FLAGS, + G_TLS_CERTIFICATE_VALIDATE_ALL, + G_PARAM_CONSTRUCT | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); } /** @@ -632,7 +755,7 @@ g_socket_client_connect (GSocketClient *client, GCancellable *cancellable, GError **error) { - GSocketConnection *connection = NULL; + GIOStream *connection = NULL; GSocketAddressEnumerator *enumerator = NULL; GError *last_error, *tmp_error; @@ -687,7 +810,7 @@ g_socket_client_connect (GSocketClient *client, } if (g_socket_connect (socket, address, cancellable, &last_error)) - connection = g_socket_connection_factory_create_connection (socket); + connection = (GIOStream *)g_socket_connection_factory_create_connection (socket); if (connection && G_IS_PROXY_ADDRESS (address) && @@ -717,31 +840,16 @@ g_socket_client_connect (GSocketClient *client, } else if (proxy) { - GIOStream *io_stream; + GIOStream *proxy_connection; - io_stream = g_proxy_connect (proxy, - G_IO_STREAM (connection), - proxy_addr, - cancellable, - &last_error); + proxy_connection = g_proxy_connect (proxy, + connection, + proxy_addr, + cancellable, + &last_error); g_object_unref (connection); + connection = proxy_connection; g_object_unref (proxy); - - if (io_stream) - { - if (G_IS_SOCKET_CONNECTION (io_stream)) - connection = G_SOCKET_CONNECTION (io_stream); - else - { - connection = g_tcp_wrapper_connection_new (G_POLLABLE_IO_STREAM (io_stream), - socket); - g_object_unref (io_stream); - } - } - else - { - connection = NULL; - } } else if (!g_hash_table_lookup_extended (client->priv->app_proxies, protocol, NULL, NULL)) @@ -754,12 +862,41 @@ g_socket_client_connect (GSocketClient *client, } } + if (connection && client->priv->tls) + { + GTlsClientConnection *tlsconn; + + tlsconn = g_tls_client_connection_new (connection, connectable, &last_error); + g_object_unref (connection); + connection = (GIOStream *)tlsconn; + + if (tlsconn) + { + g_tls_client_connection_set_validation_flags (tlsconn, client->priv->tls_validation_flags); + if (!g_tls_connection_handshake (G_TLS_CONNECTION (tlsconn), + cancellable, &last_error)) + { + g_object_unref (tlsconn); + connection = NULL; + } + } + } + + if (connection && !G_IS_SOCKET_CONNECTION (connection)) + { + GSocketConnection *wrapper_connection; + + wrapper_connection = g_tcp_wrapper_connection_new (connection, socket); + g_object_unref (connection); + connection = (GIOStream *)wrapper_connection; + } + g_object_unref (socket); g_object_unref (address); } g_object_unref (enumerator); - return connection; + return G_SOCKET_CONNECTION (connection); } /** @@ -927,10 +1064,11 @@ typedef struct GCancellable *cancellable; GSocketClient *client; + GSocketConnectable *connectable; GSocketAddressEnumerator *enumerator; GProxyAddress *proxy_addr; GSocket *current_socket; - GSocketConnection *connection; + GIOStream *connection; GError *last_error; } GSocketClientAsyncConnectData; @@ -946,6 +1084,16 @@ g_socket_client_async_connect_complete (GSocketClientAsyncConnectData *data) { g_assert (data->connection); + if (!G_IS_SOCKET_CONNECTION (data->connection)) + { + GSocketConnection *wrapper_connection; + + wrapper_connection = g_tcp_wrapper_connection_new (data->connection, + data->current_socket); + g_object_unref (data->connection); + data->connection = (GIOStream *)wrapper_connection; + } + g_simple_async_result_set_op_res_gpointer (data->result, data->connection, g_object_unref); @@ -953,6 +1101,7 @@ g_socket_client_async_connect_complete (GSocketClientAsyncConnectData *data) g_simple_async_result_complete (data->result); g_object_unref (data->result); + g_object_unref (data->connectable); g_object_unref (data->enumerator); if (data->cancellable) g_object_unref (data->cancellable); @@ -987,45 +1136,103 @@ enumerator_next_async (GSocketClientAsyncConnectData *data) } static void -g_socket_client_proxy_connect_callback (GObject *object, +g_socket_client_tls_handshake_callback (GObject *object, GAsyncResult *result, gpointer user_data) { GSocketClientAsyncConnectData *data = user_data; - GIOStream *io_stream; - io_stream = g_proxy_connect_finish (G_PROXY (object), - result, - &data->last_error); - g_object_unref (data->connection); - - if (io_stream) + if (g_tls_connection_handshake_finish (G_TLS_CONNECTION (object), + result, + &data->last_error)) { - if (G_IS_SOCKET_CONNECTION (io_stream)) - data->connection = G_SOCKET_CONNECTION (io_stream); - else - { - data->connection = g_tcp_wrapper_connection_new (G_POLLABLE_IO_STREAM (io_stream), - data->current_socket); - g_object_unref (io_stream); - } + g_object_unref (data->connection); + data->connection = G_IO_STREAM (object); } else { - data->connection = NULL; + g_object_unref (object); g_object_unref (data->current_socket); data->current_socket = NULL; + g_object_unref (data->connection); + data->connection = NULL; + + enumerator_next_async (data); } g_socket_client_async_connect_complete (data); } +static void +g_socket_client_tls_handshake (GSocketClientAsyncConnectData *data) +{ + GTlsClientConnection *tlsconn; + + if (!data->client->priv->tls) + { + g_socket_client_async_connect_complete (data); + return; + } + + tlsconn = g_tls_client_connection_new (data->connection, + data->connectable, + &data->last_error); + if (tlsconn) + { + g_tls_client_connection_set_validation_flags (tlsconn, data->client->priv->tls_validation_flags); + g_tls_connection_handshake_async (G_TLS_CONNECTION (tlsconn), + G_PRIORITY_DEFAULT, + data->cancellable, + g_socket_client_tls_handshake_callback, + data); + } + else + { + g_object_unref (data->current_socket); + data->current_socket = NULL; + g_object_unref (data->connection); + data->connection = NULL; + + enumerator_next_async (data); + } +} + +static void +g_socket_client_proxy_connect_callback (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + GSocketClientAsyncConnectData *data = user_data; + + g_object_unref (data->connection); + data->connection = g_proxy_connect_finish (G_PROXY (object), + result, + &data->last_error); + if (!data->connection) + { + g_object_unref (data->current_socket); + data->current_socket = NULL; + + enumerator_next_async (data); + return; + } + + g_socket_client_tls_handshake (data); +} + static void g_socket_client_proxy_connect (GSocketClientAsyncConnectData *data) { GProxy *proxy; - const gchar *protocol = g_proxy_address_get_protocol (data->proxy_addr); + const gchar *protocol; + if (!data->proxy_addr) + { + g_socket_client_tls_handshake (data); + return; + } + + protocol = g_proxy_address_get_protocol (data->proxy_addr); proxy = g_proxy_get_default_for_protocol (protocol); /* The connection should not be anything else then TCP Connection, @@ -1050,7 +1257,7 @@ g_socket_client_proxy_connect (GSocketClientAsyncConnectData *data) else if (proxy) { g_proxy_connect_async (proxy, - G_IO_STREAM (data->connection), + data->connection, data->proxy_addr, data->cancellable, g_socket_client_proxy_connect_callback, @@ -1066,6 +1273,8 @@ g_socket_client_proxy_connect (GSocketClientAsyncConnectData *data) _("Proxy protocol '%s' is not supported."), protocol); + g_object_unref (data->current_socket); + data->current_socket = NULL; g_object_unref (data->connection); data->connection = NULL; g_object_unref (data->current_socket); @@ -1080,13 +1289,10 @@ g_socket_client_socket_connected (GSocketClientAsyncConnectData *data) { g_socket_set_blocking (data->current_socket, TRUE); - data->connection = + data->connection = (GIOStream *) g_socket_connection_factory_create_connection (data->current_socket); - if (data->proxy_addr) - g_socket_client_proxy_connect (data); - else - g_socket_client_async_connect_complete (data); + g_socket_client_proxy_connect (data); } static gboolean @@ -1243,6 +1449,10 @@ g_socket_client_connect_async (GSocketClient *client, data->client = client; if (cancellable) data->cancellable = g_object_ref (cancellable); + else + data->cancellable = NULL; + data->last_error = NULL; + data->connectable = g_object_ref (connectable); if (can_use_proxy (client)) data->enumerator = g_socket_connectable_proxy_enumerate (connectable); diff --git a/gio/gsocketclient.h b/gio/gsocketclient.h index 2586f707a..180bedd0e 100644 --- a/gio/gsocketclient.h +++ b/gio/gsocketclient.h @@ -89,6 +89,13 @@ gboolean g_socket_client_get_enable_proxy (GSocket void g_socket_client_set_enable_proxy (GSocketClient *client, gboolean enable); +gboolean g_socket_client_get_tls (GSocketClient *client); +void g_socket_client_set_tls (GSocketClient *client, + gboolean tls); +GTlsCertificateFlags g_socket_client_get_tls_validation_flags (GSocketClient *client); +void g_socket_client_set_tls_validation_flags (GSocketClient *client, + GTlsCertificateFlags flags); + GSocketConnection * g_socket_client_connect (GSocketClient *client, GSocketConnectable *connectable, GCancellable *cancellable, diff --git a/gio/gtlsbackend.c b/gio/gtlsbackend.c new file mode 100644 index 000000000..6c93c48a7 --- /dev/null +++ b/gio/gtlsbackend.c @@ -0,0 +1,201 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright © 2010 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "glib.h" + +#include "gtlsbackend.h" +#include "gdummytlsbackend.h" +#include "gioenumtypes.h" +#include "giomodule-priv.h" + +/** + * SECTION:gtls + * @title: TLS Overview + * @short_description: TLS (aka SSL) support for #GSocketConnection + * @include: gio/gio.h + * + * #GTlsConnection and related classes provide TLS (Transport Layer + * Security, previously known as SSL, Secure Sockets Layer) support for + * gio-based network streams. + * + * In the simplest case, for a client connection, you can just set the + * #GSocketClient:tls flag on a #GSocketClient, and then any + * connections created by that client will have TLS negotiated + * automatically, using appropriate default settings, and rejecting + * any invalid or self-signed certificates (unless you change that + * default by setting the #GSocketClient:tls-validation-flags + * property). The returned object will be a #GTcpWrapperConnection, + * which wraps the underlying #GTlsClientConnection. + * + * For greater control, you can create your own #GTlsClientConnection, + * wrapping a #GSocketConnection (or an arbitrary #GIOStream with + * pollable input and output streams) and then connect to its signals, + * such as #GTlsConnection::accept-certificate, before starting the + * handshake. + * + * Server-side TLS is similar, using #GTlsServerConnection. At the + * moment, there is no support for automatically wrapping server-side + * connections in the way #GSocketClient does for client-side + * connections. + */ + +/** + * SECTION:gtlsbackend + * @title: GTlsBackend + * @short_description: TLS backend implementation + * @include: gio/gio.h + */ + +/** + * GTlsBackend: + * + * Type implemented by TLS #GIOModules to provide access to additional + * TLS-related types. + * + * Since: 2.28 + */ + +G_DEFINE_INTERFACE (GTlsBackend, g_tls_backend, G_TYPE_OBJECT); + +static void +g_tls_backend_default_init (GTlsBackendInterface *iface) +{ +} + +static gpointer +get_default_tls_backend (gpointer arg) +{ + const char *use_this; + GList *extensions; + GIOExtensionPoint *ep; + GIOExtension *extension; + + _g_io_modules_ensure_loaded (); + + ep = g_io_extension_point_lookup (G_TLS_BACKEND_EXTENSION_POINT_NAME); + + use_this = g_getenv ("GIO_USE_TLS"); + if (use_this) + { + extension = g_io_extension_point_get_extension_by_name (ep, use_this); + if (extension) + return g_object_new (g_io_extension_get_type (extension), NULL); + } + + extensions = g_io_extension_point_get_extensions (ep); + if (extensions) + { + extension = extensions->data; + return g_object_new (g_io_extension_get_type (extension), NULL); + } + + return NULL; +} + +/** + * g_tls_backend_get_default: + * + * Gets the default #GTlsBackend for the system. + * + * Returns: a #GTlsBackend + * + * Since: 2.28 + */ +GTlsBackend * +g_tls_backend_get_default (void) +{ + static GOnce once_init = G_ONCE_INIT; + + return g_once (&once_init, get_default_tls_backend, NULL); +} + +/** + * g_tls_backend_supports_tls: + * @backend: the #GTlsBackend + * + * Checks if TLS is supported; if this returns %FALSE for the default + * #GTlsBackend, it means no "real" TLS backend is available. + * + * Return value: whether or not TLS is supported + * + * Since: 2.28 + */ +gboolean +g_tls_backend_supports_tls (GTlsBackend *backend) +{ + if (G_TLS_BACKEND_GET_INTERFACE (backend)->supports_tls) + return G_TLS_BACKEND_GET_INTERFACE (backend)->supports_tls (backend); + else if (G_IS_DUMMY_TLS_BACKEND (backend)) + return FALSE; + else + return TRUE; +} + +/** + * g_tls_backend_get_certificate_type: + * @backend: the #GTlsBackend + * + * Gets the #GType of @backend's #GTlsCertificate implementation. + * + * Return value: the #GType of @backend's #GTlsCertificate + * implementation. + * + * Since: 2.28 + */ +GType +g_tls_backend_get_certificate_type (GTlsBackend *backend) +{ + return G_TLS_BACKEND_GET_INTERFACE (backend)->get_certificate_type (); +} + +/** + * g_tls_backend_get_client_connection_type: + * @backend: the #GTlsBackend + * + * Gets the #GType of @backend's #GTlsClientConnection implementation. + * + * Return value: the #GType of @backend's #GTlsClientConnection + * implementation. + * + * Since: 2.28 + */ +GType +g_tls_backend_get_client_connection_type (GTlsBackend *backend) +{ + return G_TLS_BACKEND_GET_INTERFACE (backend)->get_client_connection_type (); +} + +/** + * g_tls_backend_get_server_connection_type: + * @backend: the #GTlsBackend + * + * Gets the #GType of @backend's #GTlsServerConnection implementation. + * + * Return value: the #GType of @backend's #GTlsServerConnection + * implementation. + * + * Since: 2.28 + */ +GType +g_tls_backend_get_server_connection_type (GTlsBackend *backend) +{ + return G_TLS_BACKEND_GET_INTERFACE (backend)->get_server_connection_type (); +} diff --git a/gio/gtlsbackend.h b/gio/gtlsbackend.h new file mode 100644 index 000000000..24ae91122 --- /dev/null +++ b/gio/gtlsbackend.h @@ -0,0 +1,92 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __G_TLS_BACKEND_H__ +#define __G_TLS_BACKEND_H__ + +#include + +G_BEGIN_DECLS + +/** + * G_TLS_BACKEND_EXTENSION_POINT_NAME: + * + * Extension point for TLS functionality via #GTlsBackend. + * See Extending GIO. + */ +#define G_TLS_BACKEND_EXTENSION_POINT_NAME "gio-tls-backend" + +#define G_TYPE_TLS_BACKEND (g_tls_backend_get_type ()) +#define G_TLS_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_TLS_BACKEND, GTlsBackend)) +#define G_IS_TLS_BACKEND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_TLS_BACKEND)) +#define G_TLS_BACKEND_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_TLS_BACKEND, GTlsBackendInterface)) + +/** + * GTlsBackend: + * + * TLS (Transport Layer Security, aka SSL) backend. This is an + * internal type used to coordinate the different classes implemented + * by a TLS backend. + * + * Since: 2.28 + */ + +typedef struct _GTlsBackend GTlsBackend; +typedef struct _GTlsBackendInterface GTlsBackendInterface; + +/** + * GTlsBackendInterface: + * @g_iface: The parent interface. + * @get_certificate_type: returns the #GTlsCertificate implementation type + * @get_client_connection_type: returns the #GTlsClientConnection implementation type + * @get_server_connection_type: returns the #GTlsServerConnection implementation type + * + * Provides an interface for describing TLS-related types. + * + * Since: 2.28 + */ +struct _GTlsBackendInterface +{ + GTypeInterface g_iface; + + /* methods */ + gboolean ( *supports_tls) (GTlsBackend *backend); + GType ( *get_certificate_type) (void); + GType ( *get_client_connection_type) (void); + GType ( *get_server_connection_type) (void); +}; + +GType g_tls_backend_get_type (void) G_GNUC_CONST; + +GTlsBackend *g_tls_backend_get_default (void); + +gboolean g_tls_backend_supports_tls (GTlsBackend *backend); + +GType g_tls_backend_get_certificate_type (GTlsBackend *backend); +GType g_tls_backend_get_client_connection_type (GTlsBackend *backend); +GType g_tls_backend_get_server_connection_type (GTlsBackend *backend); + +G_END_DECLS + +#endif /* __G_TLS_BACKEND_H__ */ diff --git a/gio/gtlscertificate.c b/gio/gtlscertificate.c new file mode 100644 index 000000000..876049cb9 --- /dev/null +++ b/gio/gtlscertificate.c @@ -0,0 +1,486 @@ +/* GIO - GLib Input, Output and Certificateing Library + * + * Copyright (C) 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "gtlscertificate.h" + +#include +#include "ginitable.h" +#include "gtlsbackend.h" +#include "gtlsconnection.h" +#include "glibintl.h" + +/** + * SECTION: gtlscertificate + * @title: GTlsCertificate + * @short_description: a TLS certificate + * @see_also: #GTlsConnection + * + * A certificate used for TLS authentication and encryption. + * This can represent either a public key only (eg, the certificate + * received by a client from a server), or the combination of + * a public key and a private key (which is needed when acting as a + * #GTlsServerConnection). + * + * Since: 2.28 + */ + +/** + * GTlsCertificate: + * + * Abstract base class for TLS certificate types. + * + * Since: 2.28 + */ + +G_DEFINE_ABSTRACT_TYPE (GTlsCertificate, g_tls_certificate, G_TYPE_OBJECT); + +struct _GTlsCertificatePrivate +{ + GTlsCertificate *issuer; +}; + +enum +{ + PROP_0, + + PROP_CERTIFICATE, + PROP_CERTIFICATE_PEM, + PROP_PRIVATE_KEY, + PROP_PRIVATE_KEY_PEM, + PROP_ISSUER +}; + +static void +g_tls_certificate_init (GTlsCertificate *cert) +{ + cert->priv = G_TYPE_INSTANCE_GET_PRIVATE (cert, + G_TYPE_TLS_CERTIFICATE, + GTlsCertificatePrivate); +} + +static void +g_tls_certificate_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GTlsCertificate *cert = G_TLS_CERTIFICATE (object); + + switch (prop_id) + { + case PROP_ISSUER: + g_value_set_object (value, cert->priv->issuer); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +g_tls_certificate_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GTlsCertificate *cert = G_TLS_CERTIFICATE (object); + + switch (prop_id) + { + case PROP_ISSUER: + cert->priv->issuer = g_value_dup_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +g_tls_certificate_finalize (GObject *object) +{ + GTlsCertificate *cert = G_TLS_CERTIFICATE (object); + + if (cert->priv->issuer) + g_object_unref (cert->priv->issuer); + + G_OBJECT_CLASS (g_tls_certificate_parent_class)->finalize (object); +} + +static void +g_tls_certificate_class_init (GTlsCertificateClass *class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (class); + + g_type_class_add_private (class, sizeof (GTlsCertificatePrivate)); + + gobject_class->set_property = g_tls_certificate_set_property; + gobject_class->get_property = g_tls_certificate_get_property; + gobject_class->finalize = g_tls_certificate_finalize; + + /** + * GTlsCertificate:certificate: + * + * The DER (binary) encoded representation of the certificate's + * public key. This property and the + * #GTlsCertificate:certificate-pem property represent the same + * data, just in different forms. + * + * Since: 2.28 + */ + g_object_class_install_property (gobject_class, PROP_CERTIFICATE, + g_param_spec_boxed ("certificate", + P_("Certificate"), + P_("The DER representation of the certificate"), + G_TYPE_BYTE_ARRAY, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * GTlsCertificate:certificate-pem: + * + * The PEM (ASCII) encoded representation of the certificate's + * public key. This property and the #GTlsCertificate:certificate + * property represent the same data, just in different forms. + * + * Since: 2.28 + */ + g_object_class_install_property (gobject_class, PROP_CERTIFICATE_PEM, + g_param_spec_string ("certificate-pem", + P_("Certificate (PEM)"), + P_("The PEM representation of the certificate"), + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * GTlsCertificate:private-key: + * + * The DER (binary) encoded representation of the certificate's + * private key. This property (or the + * #GTlsCertificate:private-key-pem property) can be set when + * constructing a key (eg, from a file), but cannot be read. + * + * Since: 2.28 + */ + g_object_class_install_property (gobject_class, PROP_PRIVATE_KEY, + g_param_spec_boxed ("private-key", + P_("Private key"), + P_("The DER representation of the certificate's private key"), + G_TYPE_BYTE_ARRAY, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * GTlsCertificate:private-key-pem: + * + * The PEM (ASCII) encoded representation of the certificate's + * private key. This property (or the #GTlsCertificate:private-key + * property) can be set when constructing a key (eg, from a file), + * but cannot be read. + * + * Since: 2.28 + */ + g_object_class_install_property (gobject_class, PROP_PRIVATE_KEY_PEM, + g_param_spec_string ("private-key-pem", + P_("Private key (PEM)"), + P_("The PEM representation of the certificate's private key"), + NULL, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * GTlsCertificate:issuer: + * + * A #GTlsCertificate representing the entity that issued this + * certificate. If %NULL, this means that the certificate is either + * self-signed, or else the certificate of the issuer is not + * available. + * + * Since: 2.28 + */ + g_object_class_install_property (gobject_class, PROP_ISSUER, + g_param_spec_object ("issuer", + P_("Issuer"), + P_("The certificate for the issuing entity"), + G_TYPE_TLS_CERTIFICATE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} + +static GTlsCertificate * +g_tls_certificate_new_internal (const gchar *certificate_pem, + const gchar *private_key_pem, + GError **error) +{ + GObject *cert; + GTlsBackend *backend; + + backend = g_tls_backend_get_default (); + + cert = g_initable_new (g_tls_backend_get_certificate_type (backend), + NULL, error, + "certificate-pem", certificate_pem, + "private-key-pem", private_key_pem, + NULL); + return G_TLS_CERTIFICATE (cert); +} + +#define PEM_CERTIFICATE_HEADER "-----BEGIN CERTIFICATE-----" +#define PEM_CERTIFICATE_FOOTER "-----END CERTIFICATE-----" +#define PEM_PRIVKEY_HEADER "-----BEGIN RSA PRIVATE KEY-----" +#define PEM_PRIVKEY_FOOTER "-----END RSA PRIVATE KEY-----" + +static GTlsCertificate * +parse_next_pem_certificate (const gchar **data, + const gchar *data_end, + gboolean required, + GError **error) +{ + const gchar *start, *end, *next; + gchar *cert_pem, *privkey_pem = NULL; + GTlsCertificate *cert; + + start = g_strstr_len (*data, data_end - *data, PEM_CERTIFICATE_HEADER); + if (!start) + { + if (required) + { + g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE, + _("No PEM-encoded certificate found")); + } + return NULL; + } + + end = g_strstr_len (start, data_end - start, PEM_CERTIFICATE_FOOTER); + if (!end) + { + g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE, + _("Could not parse PEM-encoded certificate")); + return NULL; + } + end += strlen (PEM_CERTIFICATE_FOOTER); + while (*end == '\r' || *end == '\n') + end++; + + cert_pem = g_strndup (start, end - start); + + *data = end; + + next = g_strstr_len (*data, data_end - *data, PEM_CERTIFICATE_HEADER); + start = g_strstr_len (*data, data_end - *data, PEM_PRIVKEY_HEADER); + if (start) + end = g_strstr_len (start, data_end - start, PEM_PRIVKEY_FOOTER); + + if (start && (!next || start < next)) + { + if (!end || (next && end > next)) + { + g_set_error_literal (error, G_TLS_ERROR, G_TLS_ERROR_BAD_CERTIFICATE, + _("Could not parse PEM-encoded private key")); + return NULL; + } + + end += strlen (PEM_PRIVKEY_FOOTER); + while (*end == '\r' || *end == '\n') + end++; + + privkey_pem = g_strndup (start, end - start); + + *data = end + strlen (PEM_PRIVKEY_FOOTER); + } + + cert = g_tls_certificate_new_internal (cert_pem, privkey_pem, error); + g_free (cert_pem); + g_free (privkey_pem); + + return cert; +} + +/** + * g_tls_certificate_new_from_pem: + * @data: PEM-encoded certificate data + * @length: the length of @data, or -1 if it's 0-terminated. + * @error: #GError for error reporting, or %NULL to ignore. + * + * Creates a new #GTlsCertificate from the PEM-encoded data in @data. + * If @data includes both a certificate and a private key, then the + * returned certificate will include the private key data as well. + * + * If @data includes multiple certificates, only the first one will be + * parsed. + * + * Return value: the new certificate, or %NULL if @data is invalid + * + * Since: 2.28 + */ +GTlsCertificate * +g_tls_certificate_new_from_pem (const gchar *data, + gssize length, + GError **error) +{ + const gchar *data_end; + + g_return_val_if_fail (data != NULL, NULL); + + if (length == -1) + data_end = data + strlen (data); + else + data_end = data + length; + return parse_next_pem_certificate (&data, data_end, TRUE, error); +} + +/** + * g_tls_certificate_new_from_file: + * @file: file containing a PEM-encoded certificate to import + * @error: #GError for error reporting, or %NULL to ignore. + * + * Creates a #GTlsCertificate from the PEM-encoded data in @file. If + * @file cannot be read or parsed, the function will return %NULL and + * set @error. Otherwise, this behaves like g_tls_certificate_new(). + * + * Return value: the new certificate, or %NULL on error + * + * Since: 2.28 + */ +GTlsCertificate * +g_tls_certificate_new_from_file (const gchar *file, + GError **error) +{ + GTlsCertificate *cert; + gchar *contents; + gsize length; + + if (!g_file_get_contents (file, &contents, &length, error)) + return NULL; + + cert = g_tls_certificate_new_from_pem (contents, length, error); + g_free (contents); + return cert; +} + +/** + * g_tls_certificate_new_from_files: + * @cert_file: file containing a PEM-encoded certificate to import + * @key_file: file containing a PEM-encoded private key to import + * @error: #GError for error reporting, or %NULL to ignore. + * + * Creates a #GTlsCertificate from the PEM-encoded data in @cert_file + * and @key_file. If either file cannot be read or parsed, the + * function will return %NULL and set @error. Otherwise, this behaves + * like g_tls_certificate_new(). + * + * Return value: the new certificate, or %NULL on error + * + * Since: 2.28 + */ +GTlsCertificate * +g_tls_certificate_new_from_files (const gchar *cert_file, + const gchar *key_file, + GError **error) +{ + GTlsCertificate *cert; + gchar *cert_data, *key_data; + + if (!g_file_get_contents (cert_file, &cert_data, NULL, error)) + return NULL; + if (!g_file_get_contents (key_file, &key_data, NULL, error)) + { + g_free (cert_data); + return NULL; + } + + cert = g_tls_certificate_new_internal (cert_data, key_data, error); + g_free (cert_data); + g_free (key_data); + return cert; +} + +/** + * g_tls_certificate_list_new_from_file: + * @file: file containing PEM-encoded certificates to import + * @error: #GError for error reporting, or %NULL to ignore. + * + * Creates one or more #GTlsCertificates from the PEM-encoded + * data in @file. If @file cannot be read or parsed, the function will + * return %NULL and set @error. If @file does not contain any + * PEM-encoded certificates, this will return an empty list and not + * set @error. + * + * Return value: (element-type Gio.TlsCertificate) (transfer full): a + * #GList containing #GTlsCertificate objects. You must free the list + * and its contents when you are done with it. + * + * Since: 2.28 + */ +GList * +g_tls_certificate_list_new_from_file (const gchar *file, + GError **error) +{ + GTlsCertificate *cert; + GList *list, *l; + gchar *contents, *end; + const gchar *p; + gsize length; + + if (!g_file_get_contents (file, &contents, &length, error)) + return NULL; + + list = NULL; + end = contents + length; + p = contents; + while (p && *p) + { + cert = parse_next_pem_certificate (&p, end, FALSE, error); + if (!cert) + { + for (l = list; l; l = l->next) + g_object_unref (l->data); + g_list_free (list); + list = NULL; + break; + } + list = g_list_prepend (list, cert); + } + + return g_list_reverse (list); +} + + +/** + * g_tls_certificate_get_issuer: + * @cert: a #GTlsCertificate + * + * Gets the #GTlsCertificate representing @cert's issuer, if known + * + * Return value: (transfer none): The certificate of @cert's issuer, + * or %NULL if @cert is self-signed or signed with an unknown + * certificate. + * + * Since: 2.28 + */ +GTlsCertificate * +g_tls_certificate_get_issuer (GTlsCertificate *cert) +{ + return cert->priv->issuer; +} diff --git a/gio/gtlscertificate.h b/gio/gtlscertificate.h new file mode 100644 index 000000000..f8a7fd161 --- /dev/null +++ b/gio/gtlscertificate.h @@ -0,0 +1,75 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __G_TLS_CERTIFICATE_H__ +#define __G_TLS_CERTIFICATE_H__ + +#include + +G_BEGIN_DECLS + +#define G_TYPE_TLS_CERTIFICATE (g_tls_certificate_get_type ()) +#define G_TLS_CERTIFICATE(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), G_TYPE_TLS_CERTIFICATE, GTlsCertificate)) +#define G_TLS_CERTIFICATE_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_TLS_CERTIFICATE, GTlsCertificateClass)) +#define G_IS_TLS_CERTIFICATE(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_TLS_CERTIFICATE)) +#define G_IS_TLS_CERTIFICATE_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_TLS_CERTIFICATE)) +#define G_TLS_CERTIFICATE_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), G_TYPE_TLS_CERTIFICATE, GTlsCertificateClass)) + +typedef struct _GTlsCertificateClass GTlsCertificateClass; +typedef struct _GTlsCertificatePrivate GTlsCertificatePrivate; + +struct _GTlsCertificate { + GObject parent_instance; + + GTlsCertificatePrivate *priv; +}; + +struct _GTlsCertificateClass +{ + GObjectClass parent_class; + + /*< private >*/ + /* Padding for future expansion */ + gpointer padding[8]; +}; + +GType g_tls_certificate_get_type (void) G_GNUC_CONST; + +GTlsCertificate *g_tls_certificate_new_from_pem (const gchar *data, + gssize length, + GError **error); + +GTlsCertificate *g_tls_certificate_new_from_file (const gchar *file, + GError **error); +GTlsCertificate *g_tls_certificate_new_from_files (const gchar *cert_file, + const gchar *key_file, + GError **error); +GList *g_tls_certificate_list_new_from_file (const gchar *file, + GError **error); + +GTlsCertificate *g_tls_certificate_get_issuer (GTlsCertificate *cert); + +G_END_DECLS + +#endif /* __G_TLS_CERTIFICATE_H__ */ diff --git a/gio/gtlsclientconnection.c b/gio/gtlsclientconnection.c new file mode 100644 index 000000000..1faea96d4 --- /dev/null +++ b/gio/gtlsclientconnection.c @@ -0,0 +1,333 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright © 2010 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "glib.h" + +#include "gtlsclientconnection.h" +#include "ginitable.h" +#include "gioenumtypes.h" +#include "gio-marshal.h" +#include "gsocket.h" +#include "gsocketconnectable.h" +#include "gtlsbackend.h" +#include "gtlscertificate.h" +#include "glibintl.h" + +/** + * SECTION:gtlsclientconnection + * @short_description: TLS client-side connection + * @include: gio/gio.h + * + * #GTlsClientConnection is the client-side subclass of + * #GTlsConnection, representing a client-side TLS connection. + * + * Since: 2.28 + */ + +/** + * GTlsClientConnection: + * + * Abstract base class for the backend-specific client connection + * type. + * + * Since: 2.28 + */ + +G_DEFINE_INTERFACE (GTlsClientConnection, g_tls_client_connection, G_TYPE_TLS_CONNECTION) + +static void +g_tls_client_connection_default_init (GTlsClientConnectionInterface *iface) +{ + /** + * GTlsClientConnection:validation-flags: + * + * What steps to perform when validating a certificate received from + * a server. Server certificates that fail to validate in all of the + * ways indicated here will be rejected unless the application + * overrides the default via #GTlsConnection::accept-certificate. + * + * Since: 2.28 + */ + g_object_interface_install_property (iface, + g_param_spec_flags ("validation-flags", + P_("Validation flags"), + P_("What certificate validation to perform"), + G_TYPE_TLS_CERTIFICATE_FLAGS, + G_TLS_CERTIFICATE_VALIDATE_ALL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); + + /** + * GTlsClientConnection:server-identity: + * + * A #GSocketConnectable describing the identity of the server that + * is expected on the other end of the connection. + * + * If the %G_TLS_CERTIFICATE_BAD_IDENTITY flag is set in + * #GTlsClientConnection:validation-flags, this object will be used + * to determine the expected identify of the remote end of the + * connection; if #GTlsClientConnection:server-identity is not set, + * or does not match the identity presented by the server, then the + * %G_TLS_CERTIFICATE_BAD_IDENTITY validation will fail. + * + * In addition to its use in verifying the server certificate, + * this is also used to give a hint to the server about what + * certificate we expect, which is useful for servers that serve + * virtual hosts. + * + * Since: 2.28 + */ + g_object_interface_install_property (iface, + g_param_spec_object ("server-identity", + P_("Server identity"), + P_("GSocketConnectable identifying the server"), + G_TYPE_SOCKET_CONNECTABLE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); + + /** + * GTlsClientConnection:use-ssl3: + * + * If %TRUE, tells the connection to use SSL 3.0 rather than trying + * to negotiate the best version of TLS or SSL to use. This can be + * used when talking to servers that don't implement version + * negotiation correctly and therefore refuse to handshake at all with + * a "modern" TLS handshake. + * + * Since: 2.28 + */ + g_object_interface_install_property (iface, + g_param_spec_boolean ("use-ssl3", + P_("Use SSL3"), + P_("Use SSL 3.0 rather than trying to use TLS 1.x"), + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); + + /** + * GTlsClientConnection:accepted-cas: + * + * A list of the distinguished names of the Certificate Authorities + * that the server will accept client certificates signed by. If the + * server requests a client certificate during the handshake, then + * this property will be set by the time the + * #GTlsConnection::need-certificate signal is emitted. + * + * Since: 2.28 + */ + g_object_interface_install_property (iface, + g_param_spec_boxed ("accepted-cas", + P_("Accepted CAs"), + P_("Distinguished names of the CAs the server accepts certificates from"), + G_TYPE_STRV, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); +} + +/** + * g_tls_client_connection_new: + * @base_io_stream: the #GIOStream to wrap + * @server_identity: (allow-none): the expected identity of the server + * @error: #GError for error reporting, or %NULL to ignore. + * + * Creates a new #GTlsClientConnection wrapping @base_io_stream (which + * must have pollable input and output streams) which is assumed to + * communicate with the server identified by @server_identity. + * + * Return value: the new #GTlsClientConnection, or %NULL on error + * + * Since: 2.28 + */ +GTlsClientConnection * +g_tls_client_connection_new (GIOStream *base_io_stream, + GSocketConnectable *server_identity, + GError **error) +{ + GObject *conn; + GTlsBackend *backend; + + backend = g_tls_backend_get_default (); + conn = g_initable_new (g_tls_backend_get_client_connection_type (backend), + NULL, error, + "base-io-stream", base_io_stream, + "server-identity", server_identity, + NULL); + return G_TLS_CLIENT_CONNECTION (conn); +} + +/** + * g_tls_client_connection_get_validation_flags: + * @conn: the #GTlsClientConnection + * + * Gets @conn's validation flags + * + * Return value: the validation flags + * + * Since: 2.28 + */ +GTlsCertificateFlags +g_tls_client_connection_get_validation_flags (GTlsClientConnection *conn) +{ + GTlsCertificateFlags flags = 0; + + g_return_val_if_fail (G_IS_TLS_CLIENT_CONNECTION (conn), 0); + + g_object_get (G_OBJECT (conn), "validation-flags", &flags, NULL); + return flags; +} + +/** + * g_tls_client_connection_set_validation_flags: + * @conn: the #GTlsClientConnection + * @flags: the #GTlsCertificatelags to use + * + * Sets @conn's validation flags, to override the default set of + * checks performed when validating a server certificate. + * + * Since: 2.28 + */ +void +g_tls_client_connection_set_validation_flags (GTlsClientConnection *conn, + GTlsCertificateFlags flags) +{ + g_return_if_fail (G_IS_TLS_CLIENT_CONNECTION (conn)); + + g_object_set (G_OBJECT (conn), "validation-flags", flags, NULL); +} + +/** + * g_tls_client_connection_get_server_identity: + * @conn: the #GTlsClientConnection + * + * Gets @conn's expected server identity + * + * Return value: a #GSocketConnectable describing the + * expected server identity, or %NULL if the expected identity is not + * known. + * + * Since: 2.28 + */ +GSocketConnectable * +g_tls_client_connection_get_server_identity (GTlsClientConnection *conn) +{ + GSocketConnectable *identity = NULL; + + g_return_val_if_fail (G_IS_TLS_CLIENT_CONNECTION (conn), 0); + + g_object_get (G_OBJECT (conn), "server-identity", &identity, NULL); + if (identity) + g_object_unref (identity); + return identity; +} + +/** + * g_tls_client_connection_set_server_identity: + * @conn: the #GTlsClientConnection + * @identity: a #GSocketConnectable describing the expected server identity + * + * Sets @conn's expected server identity, which is used both to tell + * servers on virtual hosts which certificate to present, and also + * to let @conn know what name to look for in the certificate when + * performing %G_TLS_CERTIFICATE_BAD_IDENTITY validation, if enabled. + * + * Since: 2.28 + */ +void +g_tls_client_connection_set_server_identity (GTlsClientConnection *conn, + GSocketConnectable *identity) +{ + g_return_if_fail (G_IS_TLS_CLIENT_CONNECTION (conn)); + + g_object_set (G_OBJECT (conn), "server-identity", identity, NULL); +} + +/** + * g_tls_client_connection_get_use_ssl3: + * @conn: the #GTlsClientConnection + * + * Gets whether @conn will use SSL 3.0 rather than the + * highest-supported version of TLS; see + * g_tls_client_connection_set_use_ssl3(). + * + * Return value: whether @conn will use SSL 3.0 + * + * Since: 2.28 + */ +gboolean +g_tls_client_connection_get_use_ssl3 (GTlsClientConnection *conn) +{ + gboolean use_ssl3 = FALSE; + + g_return_val_if_fail (G_IS_TLS_CLIENT_CONNECTION (conn), 0); + + g_object_get (G_OBJECT (conn), "use-ssl3", &use_ssl3, NULL); + return use_ssl3; +} + +/** + * g_tls_client_connection_set_use_ssl3: + * @conn: the #GTlsClientConnection + * @use_ssl3: whether to use SSL 3.0 + * + * If @use_ssl3 is %TRUE, this forces @conn to use SSL 3.0 rather than + * trying to properly negotiate the right version of TLS or SSL to use. + * This can be used when talking to servers that do not implement the + * fallbacks correctly and which will therefore fail to handshake with + * a "modern" TLS handshake attempt. + * + * Since: 2.28 + */ +void +g_tls_client_connection_set_use_ssl3 (GTlsClientConnection *conn, + gboolean use_ssl3) +{ + g_return_if_fail (G_IS_TLS_CLIENT_CONNECTION (conn)); + + g_object_set (G_OBJECT (conn), "use-ssl3", use_ssl3, NULL); +} + +/** + * g_tls_client_connection_get_accepted_cas: + * @conn: the #GTlsClientConnection + * + * Gets the list of distinguished names of the Certificate Authorities + * that the server will accept certificates from. This will be set + * during the TLS handshake if the server requests a certificate. + * Otherwise, it will be %NULL. + * + * Return value: (transfer full) (array zero-terminated=1): the list + * of CA names, which you must free (eg, with g_strfreev()). + * + * Since: 2.28 + */ +char ** +g_tls_client_connection_get_accepted_cas (GTlsClientConnection *conn) +{ + char **accepted_cas = NULL; + + g_return_val_if_fail (G_IS_TLS_CLIENT_CONNECTION (conn), NULL); + + g_object_get (G_OBJECT (conn), "accepted-cas", &accepted_cas, NULL); + return accepted_cas; +} diff --git a/gio/gtlsclientconnection.h b/gio/gtlsclientconnection.h new file mode 100644 index 000000000..2bfa8c451 --- /dev/null +++ b/gio/gtlsclientconnection.h @@ -0,0 +1,72 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __G_TLS_CLIENT_CONNECTION_H__ +#define __G_TLS_CLIENT_CONNECTION_H__ + +#include + +G_BEGIN_DECLS + +#define G_TYPE_TLS_CLIENT_CONNECTION (g_tls_client_connection_get_type ()) +#define G_TLS_CLIENT_CONNECTION(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), G_TYPE_TLS_CLIENT_CONNECTION, GTlsClientConnection)) +#define G_IS_TLS_CLIENT_CONNECTION(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_TLS_CLIENT_CONNECTION)) +#define G_TLS_CLIENT_CONNECTION_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), G_TYPE_TLS_CLIENT_CONNECTION, GTlsClientConnectionInterface)) + +/** + * GTlsClientConnection: + * + * TLS client-side connection; the client-side implementation of a + * #GTlsConnection + * + * Since: 2.28 + */ +typedef struct _GTlsClientConnectionInterface GTlsClientConnectionInterface; + +struct _GTlsClientConnectionInterface +{ + GTypeInterface g_iface; + +}; + +GType g_tls_client_connection_get_type (void) G_GNUC_CONST; + +GTlsClientConnection *g_tls_client_connection_new (GIOStream *base_io_stream, + GSocketConnectable *server_identity, + GError **error); + +GTlsCertificateFlags g_tls_client_connection_get_validation_flags (GTlsClientConnection *conn); +void g_tls_client_connection_set_validation_flags (GTlsClientConnection *conn, + GTlsCertificateFlags flags); +GSocketConnectable *g_tls_client_connection_get_server_identity (GTlsClientConnection *conn); +void g_tls_client_connection_set_server_identity (GTlsClientConnection *conn, + GSocketConnectable *identity); +gboolean g_tls_client_connection_get_use_ssl3 (GTlsClientConnection *conn); +void g_tls_client_connection_set_use_ssl3 (GTlsClientConnection *conn, + gboolean use_ssl3); +char ** g_tls_client_connection_get_accepted_cas (GTlsClientConnection *conn); + +G_END_DECLS + +#endif /* __G_TLS_CLIENT_CONNECTION_H__ */ diff --git a/gio/gtlsconnection.c b/gio/gtlsconnection.c new file mode 100644 index 000000000..e9e4250ed --- /dev/null +++ b/gio/gtlsconnection.c @@ -0,0 +1,720 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright © 2010 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "glib.h" + +#include "gtlsconnection.h" +#include "gcancellable.h" +#include "gioenumtypes.h" +#include "gio-marshal.h" +#include "gsocket.h" +#include "gtlsbackend.h" +#include "gtlscertificate.h" +#include "gtlsclientconnection.h" +#include "glibintl.h" + +/** + * SECTION:gtlsconnection + * @short_description: TLS connection type + * @include: gio/gio.h + * + * #GTlsConnection is the base TLS connection class type, which wraps + * a #GIOStream and provides TLS encryption on top of it. Its + * subclasses, #GTlsClientConnection and #GTlsServerConnection, + * implement client-side and server-side TLS, respectively. + * + * Since: 2.28 + */ + +/** + * GTlsConnection: + * + * Abstract base class for the backend-specific #GTlsClientConnection + * and #GTlsServerConnection types. + * + * Since: 2.28 + */ + +G_DEFINE_ABSTRACT_TYPE (GTlsConnection, g_tls_connection, G_TYPE_IO_STREAM) + +static void g_tls_connection_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void g_tls_connection_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void g_tls_connection_finalize (GObject *object); + +static gboolean g_tls_connection_certificate_accumulator (GSignalInvocationHint *ihint, + GValue *return_accu, + const GValue *handler_return, + gpointer dummy); + +enum { + NEED_CERTIFICATE, + ACCEPT_CERTIFICATE, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +enum { + PROP_0, + PROP_BASE_IO_STREAM, + PROP_REQUIRE_CLOSE_NOTIFY, + PROP_REHANDSHAKE_MODE, + PROP_CERTIFICATE, + PROP_PEER_CERTIFICATE +}; + +struct _GTlsConnectionPrivate { + GTlsCertificate *certificate, *peer_certificate; +}; + +static void +g_tls_connection_class_init (GTlsConnectionClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (GTlsConnectionPrivate)); + + gobject_class->get_property = g_tls_connection_get_property; + gobject_class->set_property = g_tls_connection_set_property; + gobject_class->finalize = g_tls_connection_finalize; + + /** + * GTlsConnection:base-io-stream: + * + * The #GIOStream that the connection wraps + * + * Since: 2.28 + */ + g_object_class_install_property (gobject_class, PROP_BASE_IO_STREAM, + g_param_spec_object ("base-io-stream", + P_("Base IOStream"), + P_("The GIOStream that the connection wraps"), + G_TYPE_IO_STREAM, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** + * GTlsConnection:require-close-notify: + * + * Whether or not proper TLS close notification is required. + * See g_tls_connection_set_require_close_notify(). + * + * Since: 2.28 + */ + g_object_class_install_property (gobject_class, PROP_REQUIRE_CLOSE_NOTIFY, + g_param_spec_boolean ("require-close-notify", + P_("Require close notify"), + P_("Whether to require proper TLS close notification"), + TRUE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * GTlsConnection:rehandshake-mode: + * + * The rehandshaking mode. See + * g_tls_connection_set_rehandshake_mode(). + * + * Since: 2.28 + */ + g_object_class_install_property (gobject_class, PROP_REHANDSHAKE_MODE, + g_param_spec_enum ("rehandshake-mode", + P_("Rehandshake mode"), + P_("When to allow rehandshaking"), + G_TYPE_TLS_REHANDSHAKE_MODE, + G_TLS_REHANDSHAKE_SAFELY, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * GTlsConnection:certificate: + * + * The connection's certificate; see + * g_tls_connection_set_certificate(). + * + * Since: 2.28 + */ + g_object_class_install_property (gobject_class, PROP_CERTIFICATE, + g_param_spec_object ("certificate", + P_("Certificate"), + P_("The connection's certificate"), + G_TYPE_TLS_CERTIFICATE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** + * GTlsConnection:peer-certificate: + * + * The connection's peer's certificate, after it has been set during + * the TLS handshake. + * + * Since: 2.28 + */ + g_object_class_install_property (gobject_class, PROP_PEER_CERTIFICATE, + g_param_spec_object ("peer-certificate", + P_("Peer Certificate"), + P_("The connection's peer's certificate"), + G_TYPE_TLS_CERTIFICATE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * GTlsConnection::need-certificate: + * @conn: a #GTlsConnection + * + * Emitted during the TLS handshake if a certificate is needed and + * one has not been set via g_tls_connection_set_certificate(). + * + * For server-side connections, a certificate is always needed, and + * the connection will fail if none is provided. + * + * For client-side connections, the signal will be emitted only if + * the server has requested a certificate; you can call + * g_tls_client_connection_get_accepted_cas() to get a list of + * Certificate Authorities that the server will accept certificates + * from. If you do not return a certificate (and have not provided + * one via g_tls_connection_set_certificate()) then the server may + * reject the handshake, in which case the operation will eventually + * fail with %G_TLS_ERROR_CERTIFICATE_REQUIRED. + * + * Note that if this signal is emitted as part of asynchronous I/O + * in the main thread, then you should not attempt to interact with + * the user before returning from the signal handler. If you want to + * let the user choose a certificate to return, you would have to + * return %NULL from the signal handler on the first attempt, and + * then after the connection attempt returns a + * %G_TLS_ERROR_CERTIFICATE_REQUIRED, you can interact with the + * user, create a new connection, and call + * g_tls_connection_set_certificate() on it before handshaking (or + * just connect to the signal again and return the certificate the + * next time). + * + * If you are doing I/O in another thread, you do not + * need to worry about this, and can simply block in the signal + * handler until the UI thread returns an answer. + * + * Return value: the certificate to send to the peer, or %NULL to + * send no certificate. If you return a certificate, the signal + * emission will be stopped and further handlers will not be called. + * + * Since: 2.28 + */ + signals[NEED_CERTIFICATE] = + g_signal_new (I_("need-certificate"), + G_TYPE_TLS_CONNECTION, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GTlsConnectionClass, need_certificate), + g_tls_connection_certificate_accumulator, NULL, + _gio_marshal_OBJECT__VOID, + G_TYPE_TLS_CERTIFICATE, 0); + + /** + * GTlsConnection::accept-certificate: + * @conn: a #GTlsConnection + * @peer_cert: the peer's #GTlsCertificate + * @errors: the problems with @peer_cert. + * + * Emitted during the TLS handshake after the peer certificate has + * been received. You can examine @peer_cert's certification path by + * calling g_tls_certificate_get_issuer() on it. + * + * For a client-side connection, @peer_cert is the server's + * certificate, and the signal will only be emitted if the + * certificate was not acceptable according to @conn's + * #GTlsClientConnection:validation_flags. If you would like the + * certificate to be accepted despite @errors, return %TRUE from the + * signal handler. Otherwise, if no handler accepts the certificate, + * the handshake will fail with %G_TLS_ERROR_BAD_CERTIFICATE. + * + * For a server-side connection, @peer_cert is the certificate + * presented by the client, if this was requested via the server's + * #GTlsServerConnection:authentication_mode. On the server side, + * the signal is always emitted when the client presents a + * certificate, and the certificate will only be accepted if a + * handler returns %TRUE. + * + * As with #GTlsConnection::need_certificate, you should not + * interact with the user during the signal emission if the signal + * was emitted as part of an asynchronous operation in the main + * thread. + * + * Return value: %TRUE to accept @peer_cert (which will also + * immediately end the signal emission). %FALSE to allow the signal + * emission to continue, which will cause the handshake to fail if + * no one else overrides it. + * + * Since: 2.28 + */ + signals[ACCEPT_CERTIFICATE] = + g_signal_new (I_("accept-certificate"), + G_TYPE_TLS_CONNECTION, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GTlsConnectionClass, accept_certificate), + g_signal_accumulator_true_handled, NULL, + _gio_marshal_BOOLEAN__OBJECT_FLAGS, + G_TYPE_BOOLEAN, 2, + G_TYPE_TLS_CERTIFICATE, + G_TYPE_TLS_CERTIFICATE_FLAGS); +} + +static void +g_tls_connection_init (GTlsConnection *conn) +{ + conn->priv = G_TYPE_INSTANCE_GET_PRIVATE (conn, G_TYPE_TLS_CONNECTION, GTlsConnectionPrivate); +} + +static void +g_tls_connection_finalize (GObject *object) +{ + GTlsConnection *conn = G_TLS_CONNECTION (object); + + if (conn->priv->certificate) + g_object_unref (conn->priv->certificate); + if (conn->priv->peer_certificate) + g_object_unref (conn->priv->peer_certificate); + + G_OBJECT_CLASS (g_tls_connection_parent_class)->finalize (object); +} + +static void +g_tls_connection_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GTlsConnection *conn = G_TLS_CONNECTION (object); + + switch (prop_id) + { + case PROP_CERTIFICATE: + g_value_set_object (value, conn->priv->certificate); + break; + + case PROP_PEER_CERTIFICATE: + g_value_set_object (value, conn->priv->peer_certificate); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +g_tls_connection_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GTlsConnection *conn = G_TLS_CONNECTION (object); + + switch (prop_id) + { + case PROP_CERTIFICATE: + g_tls_connection_set_certificate (conn, g_value_get_object (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/** + * g_tls_connection_set_certificate: + * @conn: a #GTlsConnection + * @certificate: the certificate to use for @conn + * + * This sets the certificate that @conn will present to its peer + * during the TLS handshake. If this is not set, + * #GTlsConnection::need-certificate will be emitted during the + * handshake if needed. + * + * Since: 2.28 + */ +void +g_tls_connection_set_certificate (GTlsConnection *conn, + GTlsCertificate *certificate) +{ + g_return_if_fail (G_IS_TLS_CONNECTION (conn)); + g_return_if_fail (G_IS_TLS_CERTIFICATE (certificate)); + + if (conn->priv->certificate) + g_object_unref (conn->priv->certificate); + conn->priv->certificate = certificate ? g_object_ref (certificate) : NULL; + g_object_notify (G_OBJECT (conn), "certificate"); +} + +/** + * g_tls_connection_get_certificate: + * @conn: a #GTlsConnection + * + * Gets @conn's certificate, as set by + * g_tls_connection_set_certificate() or returned from one of the + * signals. + * + * Return value: @conn's certificate, or %NULL + * + * Since: 2.28 + */ +GTlsCertificate * +g_tls_connection_get_certificate (GTlsConnection *conn) +{ + g_return_val_if_fail (G_IS_TLS_CONNECTION (conn), NULL); + + return conn->priv->certificate; +} + +/** + * g_tls_connection_get_peer_certificate: + * @conn: a #GTlsConnection + * + * Gets @conn's peer's certificate after it has been set during the + * handshake. + * + * Return value: @conn's peer's certificate, or %NULL + * + * Since: 2.28 + */ +GTlsCertificate * +g_tls_connection_get_peer_certificate (GTlsConnection *conn) +{ + g_return_val_if_fail (G_IS_TLS_CONNECTION (conn), NULL); + + return conn->priv->peer_certificate; +} + +/** + * g_tls_connection_set_require_close_notify: + * @conn: a #GTlsConnection + * @require_close_notify: whether or not to require close notification + * + * Sets whether or not @conn requires a proper TLS close notification + * before closing the connection. If this is %TRUE (the default), then + * calling g_io_stream_close() on @conn will send a TLS close + * notification, and likewise it will expect to receive a close + * notification before the connection is closed when reading, and will + * return a %G_TLS_ERROR_EOF error if the connection is closed without + * proper notification (since this may indicate a network error, or + * man-in-the-middle attack). + * + * In some protocols, the application will know whether or not the + * connection was closed cleanly based on application-level data + * (because the application-level data includes a length field, or is + * somehow self-delimiting); in this case, the close notify is + * redundant and sometimes omitted. (TLS 1.1 explicitly allows this; + * in TLS 1.0 it is technically an error, but often done anyway.) You + * can use g_tls_connection_set_require_close_notify() to tell @conn to + * allow an "unannounced" connection close, in which case it is up to + * the application to check that the data has been fully received. + * + * Since: 2.28 + */ +void +g_tls_connection_set_require_close_notify (GTlsConnection *conn, + gboolean require_close_notify) +{ + g_return_if_fail (G_IS_TLS_CONNECTION (conn)); + + g_object_set (G_OBJECT (conn), + "require-close-notify", require_close_notify, + NULL); +} + +/** + * g_tls_connection_get_require_close_notify: + * @conn: a #GTlsConnection + * + * Tests whether or not @conn requires a proper TLS close notification + * before closing the connection. See + * g_tls_connection_set_require_close_notify() for details. + * + * Return value: %TRUE if @conn requires a proper TLS close + * notification. + * + * Since: 2.28 + */ +gboolean +g_tls_connection_get_require_close_notify (GTlsConnection *conn) +{ + gboolean require_close_notify; + + g_return_val_if_fail (G_IS_TLS_CONNECTION (conn), TRUE); + + g_object_get (G_OBJECT (conn), + "require-close-notify", &require_close_notify, + NULL); + return require_close_notify; +} + +/** + * g_tls_connection_set_rehandshake_mode: + * @conn: a #GTlsConnection + * @mode: the rehandshaking mode + * + * Sets how @conn behaves with respect to rehandshaking requests. + * + * %G_TLS_REHANDSHAKE_NEVER means that it will never agree to + * rehandshake after the initial handshake is complete. (For a client, + * this means it will refuse rehandshake requests from the server, and + * for a server, this means it will close the connection with an error + * if the client attempts to rehandshake.) + * + * %G_TLS_REHANDSHAKE_SAFELY means that the connection will allow a + * rehandshake only if the other end of the connection supports the + * TLS renegotiation_info extension. This is the + * default behavior, but means that rehandshaking will not work + * against older implementations that do not support that extension. + * + * %G_TLS_REHANDSHAKE_UNSAFELY means that the connection will allow + * rehandshaking even without the + * renegotiation_info extension. On the server side + * in particular, this is not recommended, since it leaves the server + * open to certain attacks. However, this mode is necessary if you + * need to allow renegotiation with older client software. + * + * Since: 2.28 + */ +void +g_tls_connection_set_rehandshake_mode (GTlsConnection *conn, + GTlsRehandshakeMode mode) +{ + g_return_if_fail (G_IS_TLS_CONNECTION (conn)); + + g_object_set (G_OBJECT (conn), + "rehandshake-mode", mode, + NULL); +} + +/** + * g_tls_connection_get_rehandshake_mode: + * @conn: a #GTlsConnection + * + * Gets @conn rehandshaking mode. See + * g_tls_connection_set_rehandshake() for details. + * + * Return value: @conn's rehandshaking mode + * + * Since: 2.28 + */ +GTlsRehandshakeMode +g_tls_connection_get_rehandshake_mode (GTlsConnection *conn) +{ + GTlsRehandshakeMode mode; + + g_return_val_if_fail (G_IS_TLS_CONNECTION (conn), G_TLS_REHANDSHAKE_NEVER); + + g_object_get (G_OBJECT (conn), + "rehandshake-mode", &mode, + NULL); + return mode; +} + +/** + * g_tls_connection_handshake: + * @conn: a #GTlsConnection + * @cancellable: a #GCancellable, or %NULL + * @error: a #GError, or %NULL + * + * Attempts a TLS handshake on @conn. + * + * On the client side, it is never necessary to call this method; + * although the connection needs to perform a handshake after + * connecting (or after sending a "STARTTLS"-type command) and may + * need to rehandshake later if the server requests it, + * #GTlsConnection will handle this for you automatically when you try + * to send or receive data on the connection. However, you can call + * g_tls_connection_handshake() manually if you want to know for sure + * whether the initial handshake succeeded or failed (as opposed to + * just immediately trying to write to @conn's output stream, in which + * case if it fails, it may not be possible to tell if it failed + * before or after completing the handshake). + * + * Likewise, on the server side, although a handshake is necessary at + * the beginning of the communication, you do not need to call this + * function explicitly unless you want clearer error reporting. + * However, you may call g_tls_connection_handshake() later on to + * renegotiate parameters (encryption methods, etc) with the client. + * + * #GTlsConnection::accept_certificate and + * #GTlsConnection::need_certificate may be emitted during the + * handshake. + * + * Return value: success or failure + * + * Since: 2.28 + */ +gboolean +g_tls_connection_handshake (GTlsConnection *conn, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (G_IS_TLS_CONNECTION (conn), FALSE); + + return G_TLS_CONNECTION_GET_CLASS (conn)->handshake (conn, cancellable, error); +} + +/** + * g_tls_connection_handshake_async: + * @conn: a #GTlsConnection + * @io_priority: the I/O priority + * of the request. + * @cancellable: a #GCancellable, or %NULL + * @callback: callback to call when the handshake is complete + * @user_data: the data to pass to the callback function + * + * Asynchronously performs a TLS handshake on @conn. See + * g_tls_connection_handshake() for more information. + * + * Since: 2.28 + */ +void +g_tls_connection_handshake_async (GTlsConnection *conn, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_return_if_fail (G_IS_TLS_CONNECTION (conn)); + + return G_TLS_CONNECTION_GET_CLASS (conn)->handshake_async (conn, io_priority, + cancellable, + callback, user_data); +} + +/** + * g_tls_connection_handshake_finish: + * @conn: a #GTlsConnection + * @result: a #GAsyncResult. + * @error: a #GError pointer, or %NULL + * + * Finish an asynchronous TLS handshake operation. See + * g_tls_connection_handshake() for more information. + * + * Return value: %TRUE on success, %FALSE on failure, in which + * case @error will be set. + * + * Since: 2.28 + */ +gboolean +g_tls_connection_handshake_finish (GTlsConnection *conn, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (G_IS_TLS_CONNECTION (conn), FALSE); + + return G_TLS_CONNECTION_GET_CLASS (conn)->handshake_finish (conn, result, error); +} + +/** + * g_tls_error_quark: + * + * Gets the TLS error quark. + * + * Return value: a #GQuark. + * + * Since: 2.28 + */ +GQuark +g_tls_error_quark (void) +{ + return g_quark_from_static_string ("g-tls-error-quark"); +} + + +static gboolean +g_tls_connection_certificate_accumulator (GSignalInvocationHint *ihint, + GValue *return_accu, + const GValue *handler_return, + gpointer dummy) +{ + GTlsCertificate *cert; + + cert = g_value_get_object (handler_return); + if (cert) + g_value_set_object (return_accu, cert); + + return cert != NULL; +} + +/** + * g_tls_connection_emit_need_certificate: + * @conn: a #GTlsConnection + * + * Used by #GTlsConnection implementations to emit the + * #GTlsConnection::need-certificate signal. + * + * Since: 2.28 + */ +GTlsCertificate * +g_tls_connection_emit_need_certificate (GTlsConnection *conn) +{ + GTlsCertificate *cert = NULL; + + g_signal_emit (conn, signals[NEED_CERTIFICATE], 0, + &cert); + return cert; +} + +/** + * g_tls_connection_emit_accept_certificate: + * @conn: a #GTlsConnection + * + * Used by #GTlsConnection implementations to emit the + * #GTlsConnection::accept-certificate signal. + * + * Since: 2.28 + */ +gboolean +g_tls_connection_emit_accept_certificate (GTlsConnection *conn, + GTlsCertificate *peer_cert, + GTlsCertificateFlags errors) +{ + gboolean accept = FALSE; + + g_signal_emit (conn, signals[ACCEPT_CERTIFICATE], 0, + peer_cert, errors, &accept); + return accept; +} + +/** + * g_tls_connection_set_peer_certificate: + * @conn: a #GTlsConnection + * @certificate: the peer certificate + * + * Used by #GTlsConnection implementations to set the connection's + * peer certificate. + * + * Since: 2.28 + */ +void +g_tls_connection_set_peer_certificate (GTlsConnection *conn, + GTlsCertificate *certificate) +{ + if (conn->priv->peer_certificate) + g_object_unref (conn->priv->peer_certificate); + conn->priv->peer_certificate = certificate ? g_object_ref (certificate) : NULL; + g_object_notify (G_OBJECT (conn), "peer-certificate"); +} diff --git a/gio/gtlsconnection.h b/gio/gtlsconnection.h new file mode 100644 index 000000000..86f1f68f5 --- /dev/null +++ b/gio/gtlsconnection.h @@ -0,0 +1,137 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __G_TLS_CONNECTION_H__ +#define __G_TLS_CONNECTION_H__ + +#include + +G_BEGIN_DECLS + +#define G_TYPE_TLS_CONNECTION (g_tls_connection_get_type ()) +#define G_TLS_CONNECTION(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), G_TYPE_TLS_CONNECTION, GTlsConnection)) +#define G_TLS_CONNECTION_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), G_TYPE_TLS_CONNECTION, GTlsConnectionClass)) +#define G_IS_TLS_CONNECTION(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_TLS_CONNECTION)) +#define G_IS_TLS_CONNECTION_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), G_TYPE_TLS_CONNECTION)) +#define G_TLS_CONNECTION_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), G_TYPE_TLS_CONNECTION, GTlsConnectionClass)) + +/** + * GTlsConnection: + * + * TLS connection. This is an abstract type that will be subclassed by + * a TLS-library-specific subtype. + * + * Since: 2.28 + */ +typedef struct _GTlsConnectionClass GTlsConnectionClass; +typedef struct _GTlsConnectionPrivate GTlsConnectionPrivate; + +struct _GTlsConnection { + GIOStream parent_instance; + + GTlsConnectionPrivate *priv; +}; + +struct _GTlsConnectionClass +{ + GIOStreamClass parent_class; + + /* signals */ + GTlsCertificate * ( *need_certificate) (GTlsConnection *connection); + + gboolean ( *accept_certificate) (GTlsConnection *connection, + GTlsCertificate *peer_cert, + GTlsCertificateFlags errors); + + /* methods */ + gboolean ( *handshake ) (GTlsConnection *conn, + GCancellable *cancellable, + GError **error); + + void ( *handshake_async ) (GTlsConnection *conn, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean ( *handshake_finish ) (GTlsConnection *conn, + GAsyncResult *result, + GError **error); + + /*< private >*/ + /* Padding for future expansion */ + gpointer padding[8]; +}; + +GType g_tls_connection_get_type (void) G_GNUC_CONST; + +void g_tls_connection_set_certificate (GTlsConnection *conn, + GTlsCertificate *certificate); +GTlsCertificate *g_tls_connection_get_certificate (GTlsConnection *conn); + +GTlsCertificate *g_tls_connection_get_peer_certificate (GTlsConnection *conn); + +void g_tls_connection_set_require_close_notify (GTlsConnection *conn, + gboolean require_close_notify); +gboolean g_tls_connection_get_require_close_notify (GTlsConnection *conn); + +void g_tls_connection_set_rehandshake_mode (GTlsConnection *conn, + GTlsRehandshakeMode mode); +GTlsRehandshakeMode g_tls_connection_get_rehandshake_mode (GTlsConnection *conn); + +gboolean g_tls_connection_handshake (GTlsConnection *conn, + GCancellable *cancellable, + GError **error); + +void g_tls_connection_handshake_async (GTlsConnection *conn, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean g_tls_connection_handshake_finish (GTlsConnection *conn, + GAsyncResult *result, + GError **error); + +/** + * G_TLS_ERROR: + * + * Error domain for TLS. Errors in this domain will be from the + * #GTlsError enumeration. See #GError for more information on error + * domains. + */ +#define G_TLS_ERROR (g_tls_error_quark ()) +GQuark g_tls_error_quark (void); + + +/*< protected >*/ +GTlsCertificate *g_tls_connection_emit_need_certificate (GTlsConnection *conn); +gboolean g_tls_connection_emit_accept_certificate (GTlsConnection *conn, + GTlsCertificate *peer_cert, + GTlsCertificateFlags errors); + +void g_tls_connection_set_peer_certificate (GTlsConnection *conn, + GTlsCertificate *certificate); + +G_END_DECLS + +#endif /* __G_TLS_CONNECTION_H__ */ diff --git a/gio/gtlsserverconnection.c b/gio/gtlsserverconnection.c new file mode 100644 index 000000000..791a0dd7b --- /dev/null +++ b/gio/gtlsserverconnection.c @@ -0,0 +1,96 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright © 2010 Red Hat, Inc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" +#include "glib.h" + +#include "gtlsserverconnection.h" +#include "ginitable.h" +#include "gio-marshal.h" +#include "gioenumtypes.h" +#include "gsocket.h" +#include "gtlsbackend.h" +#include "gtlscertificate.h" +#include "glibintl.h" + +/** + * SECTION:gtlsserverconnection + * @short_description: TLS server-side connection + * @include: gio/gio.h + * + * #GTlsServerConnection is the server-side subclass of #GTlsConnection, + * representing a server-side TLS connection. + * + * Since: 2.28 + */ + +G_DEFINE_INTERFACE (GTlsServerConnection, g_tls_server_connection, G_TYPE_TLS_CONNECTION) + +static void +g_tls_server_connection_default_init (GTlsServerConnectionInterface *iface) +{ + /** + * GTlsServerConnection:authentication-mode: + * + * The #GTlsAuthenticationMode for the server. This can be changed + * before calling g_tls_connection_handshake() if you want to + * rehandshake with a different mode from the initial handshake. + * + * Since: 2.28 + */ + g_object_interface_install_property (iface, + g_param_spec_enum ("authentication-mode", + P_("Authentication Mode"), + P_("The client authentication mode"), + G_TYPE_TLS_AUTHENTICATION_MODE, + G_TLS_AUTHENTICATION_NONE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} + +/** + * g_tls_server_connection_new: + * @base_io_stream: the #GIOStream to wrap + * @certificate: (allow-none): the default server certificate, or %NULL + * @error: #GError for error reporting, or %NULL to ignore. + * + * Creates a new #GTlsServerConnection wrapping @base_io_stream (which + * must have pollable input and output streams). + * + * Return value: the new #GTlsServerConnection, or %NULL on error + * + * Since: 2.28 + */ +GTlsServerConnection * +g_tls_server_connection_new (GIOStream *base_io_stream, + GTlsCertificate *certificate, + GError **error) +{ + GObject *conn; + GTlsBackend *backend; + + backend = g_tls_backend_get_default (); + conn = g_initable_new (g_tls_backend_get_server_connection_type (backend), + NULL, error, + "base-io-stream", base_io_stream, + "certificate", certificate, + NULL); + return G_TLS_SERVER_CONNECTION (conn); +} diff --git a/gio/gtlsserverconnection.h b/gio/gtlsserverconnection.h new file mode 100644 index 000000000..976996eff --- /dev/null +++ b/gio/gtlsserverconnection.h @@ -0,0 +1,61 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright (C) 2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __G_TLS_SERVER_CONNECTION_H__ +#define __G_TLS_SERVER_CONNECTION_H__ + +#include + +G_BEGIN_DECLS + +#define G_TYPE_TLS_SERVER_CONNECTION (g_tls_server_connection_get_type ()) +#define G_TLS_SERVER_CONNECTION(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), G_TYPE_TLS_SERVER_CONNECTION, GTlsServerConnection)) +#define G_IS_TLS_SERVER_CONNECTION(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_TLS_SERVER_CONNECTION)) +#define G_TLS_SERVER_CONNECTION_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), G_TYPE_TLS_SERVER_CONNECTION, GTlsServerConnectionInterface)) + +/** + * GTlsServerConnection: + * + * TLS server-side connection. This is the server-side implementation + * of a #GTlsConnection. + * + * Since: 2.28 + */ +typedef struct _GTlsServerConnectionInterface GTlsServerConnectionInterface; + +struct _GTlsServerConnectionInterface +{ + GTypeInterface g_iface; + +}; + +GType g_tls_server_connection_get_type (void) G_GNUC_CONST; + +GTlsServerConnection *g_tls_server_connection_new (GIOStream *base_io_stream, + GTlsCertificate *certificate, + GError **error); + +G_END_DECLS + +#endif /* __G_TLS_SERVER_CONNECTION_H__ */ diff --git a/gio/tests/socket-client.c b/gio/tests/socket-client.c index 1f1455e5a..7c44165a6 100644 --- a/gio/tests/socket-client.c +++ b/gio/tests/socket-client.c @@ -5,17 +5,15 @@ #include #include -#include "socket-common.c" - GMainLoop *loop; gboolean verbose = FALSE; gboolean non_blocking = FALSE; gboolean use_udp = FALSE; -gboolean use_source = FALSE; int cancel_timeout = 0; int read_timeout = 0; gboolean unix_socket = FALSE; +gboolean tls = FALSE; static GOptionEntry cmd_entries[] = { {"cancel", 'c', 0, G_OPTION_ARG_INT, &cancel_timeout, @@ -26,70 +24,39 @@ static GOptionEntry cmd_entries[] = { "Be verbose", NULL}, {"non-blocking", 'n', 0, G_OPTION_ARG_NONE, &non_blocking, "Enable non-blocking i/o", NULL}, - {"use-source", 's', 0, G_OPTION_ARG_NONE, &use_source, - "Use GSource to wait for non-blocking i/o", NULL}, #ifdef G_OS_UNIX {"unix", 'U', 0, G_OPTION_ARG_NONE, &unix_socket, "Use a unix socket instead of IP", NULL}, #endif {"timeout", 't', 0, G_OPTION_ARG_INT, &read_timeout, "Time out reads after the specified number of seconds", NULL}, + {"tls", 'T', 0, G_OPTION_ARG_NONE, &tls, + "Use TLS (SSL)", NULL}, {NULL} }; +#include "socket-common.c" + static gboolean -source_ready (gpointer data, - GIOCondition condition) +accept_certificate (GTlsClientConnection *conn, GTlsCertificate *cert, + GTlsCertificateFlags errors, gpointer user_data) { - g_main_loop_quit (loop); - return FALSE; -} + g_print ("Certificate would have been rejected ( "); + if (errors & G_TLS_CERTIFICATE_UNKNOWN_CA) + g_print ("unknown-ca "); + if (errors & G_TLS_CERTIFICATE_BAD_IDENTITY) + g_print ("bad-identity "); + if (errors & G_TLS_CERTIFICATE_NOT_ACTIVATED) + g_print ("not-activated "); + if (errors & G_TLS_CERTIFICATE_EXPIRED) + g_print ("expired "); + if (errors & G_TLS_CERTIFICATE_REVOKED) + g_print ("revoked "); + if (errors & G_TLS_CERTIFICATE_INSECURE) + g_print ("insecure "); + g_print (") but accepting anyway.\n"); -static void -ensure_condition (GSocket *socket, - const char *where, - GCancellable *cancellable, - GIOCondition condition) -{ - GError *error = NULL; - GSource *source; - - if (!non_blocking) - return; - - if (use_source) - { - source = g_socket_create_source (socket, - condition, - cancellable); - g_source_set_callback (source, - (GSourceFunc) source_ready, - NULL, NULL); - g_source_attach (source, NULL); - g_source_unref (source); - g_main_loop_run (loop); - } - else - { - if (!g_socket_condition_wait (socket, condition, cancellable, &error)) - { - g_printerr ("condition wait error for %s: %s\n", - where, - error->message); - exit (1); - } - } -} - -static gpointer -cancel_thread (gpointer data) -{ - GCancellable *cancellable = data; - - g_usleep (1000*1000*cancel_timeout); - g_print ("Cancelling\n"); - g_cancellable_cancel (cancellable); - return NULL; + return TRUE; } int @@ -106,6 +73,9 @@ main (int argc, GCancellable *cancellable; GSocketAddressEnumerator *enumerator; GSocketConnectable *connectable; + GIOStream *connection; + GInputStream *istream; + GOutputStream *ostream; g_thread_init (NULL); @@ -125,6 +95,12 @@ main (int argc, return 1; } + if (use_udp && tls) + { + g_printerr ("DTLS (TLS over UDP) is not supported"); + return 1; + } + if (cancel_timeout) { cancellable = g_cancellable_new (); @@ -201,15 +177,10 @@ main (int argc, g_object_unref (address); } g_object_unref (enumerator); - g_object_unref (connectable); g_print ("Connected to %s\n", socket_address_to_string (address)); - /* TODO: Test non-blocking connect */ - if (non_blocking) - g_socket_set_blocking (socket, FALSE); - src_address = g_socket_get_local_address (socket, &error); if (!src_address) { @@ -221,6 +192,49 @@ main (int argc, socket_address_to_string (src_address)); g_object_unref (src_address); + if (use_udp) + connection = NULL; + else + connection = G_IO_STREAM (g_socket_connection_factory_create_connection (socket)); + + if (tls) + { + GTlsClientConnection *tls_conn; + + tls_conn = g_tls_client_connection_new (connection, connectable, &error); + if (!tls_conn) + { + g_printerr ("Could not create TLS connection: %s\n", + error->message); + return 1; + } + + g_signal_connect (tls_conn, "accept-certificate", + G_CALLBACK (accept_certificate), NULL); + + if (!g_tls_connection_handshake (G_TLS_CONNECTION (tls_conn), + cancellable, &error)) + { + g_printerr ("Error during TLS handshake: %s\n", + error->message); + return 1; + } + + g_object_unref (connection); + connection = G_IO_STREAM (tls_conn); + } + g_object_unref (connectable); + + if (connection) + { + istream = g_io_stream_get_input_stream (connection); + ostream = g_io_stream_get_output_stream (connection); + } + + /* TODO: Test non-blocking connect/handshake */ + if (non_blocking) + g_socket_set_blocking (socket, FALSE); + while (TRUE) { gchar buffer[4096]; @@ -233,14 +247,20 @@ main (int argc, to_send = strlen (buffer); while (to_send > 0) { - ensure_condition (socket, "send", cancellable, G_IO_OUT); if (use_udp) - size = g_socket_send_to (socket, address, - buffer, to_send, - cancellable, &error); + { + ensure_socket_condition (socket, G_IO_OUT, cancellable); + size = g_socket_send_to (socket, address, + buffer, to_send, + cancellable, &error); + } else - size = g_socket_send (socket, buffer, to_send, - cancellable, &error); + { + ensure_connection_condition (connection, G_IO_OUT, cancellable); + size = g_output_stream_write (ostream, + buffer, to_send, + cancellable, &error); + } if (size < 0) { @@ -272,14 +292,20 @@ main (int argc, to_send -= size; } - ensure_condition (socket, "receive", cancellable, G_IO_IN); if (use_udp) - size = g_socket_receive_from (socket, &src_address, + { + ensure_socket_condition (socket, G_IO_IN, cancellable); + size = g_socket_receive_from (socket, &src_address, + buffer, sizeof buffer, + cancellable, &error); + } + else + { + ensure_connection_condition (connection, G_IO_IN, cancellable); + size = g_input_stream_read (istream, buffer, sizeof buffer, cancellable, &error); - else - size = g_socket_receive (socket, buffer, sizeof buffer, - cancellable, &error); + } if (size < 0) { @@ -306,15 +332,28 @@ main (int argc, g_print ("closing socket\n"); - if (!g_socket_close (socket, &error)) + if (connection) { - g_printerr ("Error closing master socket: %s\n", - error->message); - return 1; + if (!g_io_stream_close (connection, cancellable, &error)) + { + g_printerr ("Error closing connection: %s\n", + error->message); + return 1; + } + g_object_unref (connection); + } + else + { + if (!g_socket_close (socket, &error)) + { + g_printerr ("Error closing master socket: %s\n", + error->message); + return 1; + } } - g_object_unref (G_OBJECT (socket)); - g_object_unref (G_OBJECT (address)); + g_object_unref (socket); + g_object_unref (address); return 0; } diff --git a/gio/tests/socket-common.c b/gio/tests/socket-common.c index 8d2933b0a..fdee3830a 100644 --- a/gio/tests/socket-common.c +++ b/gio/tests/socket-common.c @@ -58,3 +58,64 @@ socket_address_from_string (const char *name) #endif return NULL; } + +static gboolean +source_ready (GPollableInputStream *stream, + gpointer data) +{ + g_main_loop_quit (loop); + return FALSE; +} + +static void +ensure_socket_condition (GSocket *socket, + GIOCondition condition, + GCancellable *cancellable) +{ + GSource *source; + + if (!non_blocking) + return; + + source = g_socket_create_source (socket, condition, cancellable); + g_source_set_callback (source, + (GSourceFunc) source_ready, + NULL, NULL); + g_source_attach (source, NULL); + g_source_unref (source); + g_main_loop_run (loop); +} + +static void +ensure_connection_condition (GIOStream *stream, + GIOCondition condition, + GCancellable *cancellable) +{ + GSource *source; + + if (!non_blocking) + return; + + if (condition & G_IO_IN) + source = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (g_io_stream_get_input_stream (stream)), cancellable); + else + source = g_pollable_output_stream_create_source (G_POLLABLE_OUTPUT_STREAM (g_io_stream_get_output_stream (stream)), cancellable); + + g_source_set_callback (source, + (GSourceFunc) source_ready, + NULL, NULL); + g_source_attach (source, NULL); + g_source_unref (source); + g_main_loop_run (loop); +} + +static gpointer +cancel_thread (gpointer data) +{ + GCancellable *cancellable = data; + + g_usleep (1000*1000*cancel_timeout); + g_print ("Cancelling\n"); + g_cancellable_cancel (cancellable); + return NULL; +} diff --git a/gio/tests/socket-server.c b/gio/tests/socket-server.c index 562f1efd7..d48a5a4c0 100644 --- a/gio/tests/socket-server.c +++ b/gio/tests/socket-server.c @@ -4,8 +4,6 @@ #include #include -#include "socket-common.c" - GMainLoop *loop; int port = 7777; @@ -13,11 +11,11 @@ gboolean verbose = FALSE; gboolean dont_reuse_address = FALSE; gboolean non_blocking = FALSE; gboolean use_udp = FALSE; -gboolean use_source = FALSE; int cancel_timeout = 0; int read_timeout = 0; int delay = 0; gboolean unix_socket = FALSE; +const char *tls_cert_file = NULL; static GOptionEntry cmd_entries[] = { {"port", 'p', 0, G_OPTION_ARG_INT, &port, @@ -32,8 +30,6 @@ static GOptionEntry cmd_entries[] = { "Don't SOADDRREUSE", NULL}, {"non-blocking", 'n', 0, G_OPTION_ARG_NONE, &non_blocking, "Enable non-blocking i/o", NULL}, - {"use-source", 's', 0, G_OPTION_ARG_NONE, &use_source, - "Use GSource to wait for non-blocking i/o", NULL}, #ifdef G_OS_UNIX {"unix", 'U', 0, G_OPTION_ARG_NONE, &unix_socket, "Use a unix socket instead of IP", NULL}, @@ -42,63 +38,12 @@ static GOptionEntry cmd_entries[] = { "Delay responses by the specified number of seconds", NULL}, {"timeout", 't', 0, G_OPTION_ARG_INT, &read_timeout, "Time out reads after the specified number of seconds", NULL}, + {"tls", 'T', 0, G_OPTION_ARG_STRING, &tls_cert_file, + "Use TLS (SSL) with indicated server certificate", "CERTFILE"}, {NULL} }; -static gboolean -source_ready (gpointer data, - GIOCondition condition) -{ - g_main_loop_quit (loop); - return FALSE; -} - -static void -ensure_condition (GSocket *socket, - const char *where, - GCancellable *cancellable, - GIOCondition condition) -{ - GError *error = NULL; - GSource *source; - - if (!non_blocking) - return; - - if (use_source) - { - source = g_socket_create_source (socket, - condition, - cancellable); - g_source_set_callback (source, - (GSourceFunc) source_ready, - NULL, NULL); - g_source_attach (source, NULL); - g_source_unref (source); - g_main_loop_run (loop); - } - else - { - if (!g_socket_condition_wait (socket, condition, cancellable, &error)) - { - g_printerr ("condition wait error for %s: %s\n", - where, - error->message); - exit (1); - } - } -} - -static gpointer -cancel_thread (gpointer data) -{ - GCancellable *cancellable = data; - - g_usleep (1000*1000*cancel_timeout); - g_print ("Cancelling\n"); - g_cancellable_cancel (cancellable); - return NULL; -} +#include "socket-common.c" int main (int argc, @@ -113,6 +58,10 @@ main (int argc, GOptionContext *context; GCancellable *cancellable; char *display_addr; + GTlsCertificate *tlscert = NULL; + GIOStream *connection; + GInputStream *istream; + GOutputStream *ostream; g_thread_init (NULL); @@ -142,6 +91,23 @@ main (int argc, cancellable = NULL; } + if (tls_cert_file) + { + if (use_udp) + { + g_printerr ("DTLS (TLS over UDP) is not supported"); + return 1; + } + + tlscert = g_tls_certificate_new_from_file (tls_cert_file, &error); + if (!tlscert) + { + g_printerr ("Could not read server certificate '%s': %s\n", + tls_cert_file, error->message); + return 1; + } + } + loop = g_main_loop_new (NULL, FALSE); if (use_udp) @@ -205,7 +171,7 @@ main (int argc, g_print ("listening on %s...\n", display_addr); g_free (display_addr); - ensure_condition (socket, "accept", cancellable, G_IO_IN); + ensure_socket_condition (socket, G_IO_IN, cancellable); new_socket = g_socket_accept (socket, cancellable, &error); if (!new_socket) { @@ -233,13 +199,45 @@ main (int argc, g_object_unref (address); recv_socket = new_socket; + + connection = G_IO_STREAM (g_socket_connection_factory_create_connection (recv_socket)); + g_object_unref (new_socket); } else { recv_socket = socket; - new_socket = NULL; + connection = NULL; } + if (tlscert) + { + GTlsServerConnection *tls_conn; + + tls_conn = g_tls_server_connection_new (connection, tlscert, &error); + if (!tls_conn) + { + g_printerr ("Could not create TLS connection: %s\n", + error->message); + return 1; + } + + if (!g_tls_connection_handshake (G_TLS_CONNECTION (tls_conn), + cancellable, &error)) + { + g_printerr ("Error during TLS handshake: %s\n", + error->message); + return 1; + } + + g_object_unref (connection); + connection = G_IO_STREAM (tls_conn); + } + + if (connection) + { + istream = g_io_stream_get_input_stream (connection); + ostream = g_io_stream_get_output_stream (connection); + } while (TRUE) { @@ -247,14 +245,20 @@ main (int argc, gssize size; gsize to_send; - ensure_condition (recv_socket, "receive", cancellable, G_IO_IN); if (use_udp) - size = g_socket_receive_from (recv_socket, &address, + { + ensure_socket_condition (recv_socket, G_IO_IN, cancellable); + size = g_socket_receive_from (recv_socket, &address, + buffer, sizeof buffer, + cancellable, &error); + } + else + { + ensure_connection_condition (connection, G_IO_IN, cancellable); + size = g_input_stream_read (istream, buffer, sizeof buffer, cancellable, &error); - else - size = g_socket_receive (recv_socket, buffer, sizeof buffer, - cancellable, &error); + } if (size < 0) { @@ -288,13 +292,19 @@ main (int argc, while (to_send > 0) { - ensure_condition (recv_socket, "send", cancellable, G_IO_OUT); if (use_udp) - size = g_socket_send_to (recv_socket, address, - buffer, to_send, cancellable, &error); + { + ensure_socket_condition (recv_socket, G_IO_OUT, cancellable); + size = g_socket_send_to (recv_socket, address, + buffer, to_send, cancellable, &error); + } else - size = g_socket_send (recv_socket, buffer, to_send, - cancellable, &error); + { + ensure_connection_condition (connection, G_IO_OUT, cancellable); + size = g_output_stream_write (ostream, + buffer, to_send, + cancellable, &error); + } if (size < 0) { @@ -329,16 +339,15 @@ main (int argc, g_print ("connection closed\n"); - if (new_socket) + if (connection) { - if (!g_socket_close (new_socket, &error)) + if (!g_io_stream_close (connection, NULL, &error)) { - g_printerr ("Error closing connection socket: %s\n", + g_printerr ("Error closing connection stream: %s\n", error->message); return 1; } - - g_object_unref (G_OBJECT (new_socket)); + g_object_unref (connection); } if (!g_socket_close (socket, &error)) @@ -347,8 +356,7 @@ main (int argc, error->message); return 1; } - - g_object_unref (G_OBJECT (socket)); + g_object_unref (socket); return 0; } From d19e1a2c3c3da29e6f6c653dda9e4538e55c1838 Mon Sep 17 00:00:00 2001 From: Christian Persch Date: Sat, 27 Nov 2010 12:45:45 +0100 Subject: [PATCH 18/44] Use same variable names in .h and .c --- glib/gvariant.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/glib/gvariant.h b/glib/gvariant.h index 9491c99ae..9519d97f0 100644 --- a/glib/gvariant.h +++ b/glib/gvariant.h @@ -134,13 +134,13 @@ void g_variant_get_child (GVarian ...); GVariant * g_variant_get_child_value (GVariant *value, gsize index_); -gboolean g_variant_lookup (GVariant *value, +gboolean g_variant_lookup (GVariant *dictionary, const gchar *key, const gchar *format_string, ...); -GVariant * g_variant_lookup_value (GVariant *value, +GVariant * g_variant_lookup_value (GVariant *dictionary, const gchar *key, - const GVariantType *type); + const GVariantType *expected_type); gconstpointer g_variant_get_fixed_array (GVariant *value, gsize *n_elements, gsize element_size); From 17979707207ca004cd78991e1c04df60cb3b1cb6 Mon Sep 17 00:00:00 2001 From: Christian Persch Date: Mon, 15 Nov 2010 19:55:57 +0100 Subject: [PATCH 19/44] Typo fix --- gio/gsettings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gio/gsettings.c b/gio/gsettings.c index aa4a7bfb3..724d67f6e 100644 --- a/gio/gsettings.c +++ b/gio/gsettings.c @@ -2197,7 +2197,7 @@ g_settings_list_keys (GSettings *settings) * time and you should connect to the "children-changed" signal to watch * for those changes. Note that there is a race condition here: you may * request a child after listing it only for it to have been destroyed - * in the meantime. For this reason, g_settings_get_chuld() may return + * in the meantime. For this reason, g_settings_get_child() may return * %NULL even for a child that was listed by this function. * * For GSettings objects that are not lists, you should probably not be From 69129e806532796e44522775656c7800c389e5f8 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Sat, 27 Nov 2010 16:56:44 -0500 Subject: [PATCH 20/44] Make gio/tests/g-icon pass again It got broken in two different ways by the g_str_hash() change (354d655b) --- gio/tests/g-icon.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gio/tests/g-icon.c b/gio/tests/g-icon.c index 2bf63b7c3..52465c802 100644 --- a/gio/tests/g-icon.c +++ b/gio/tests/g-icon.c @@ -258,7 +258,7 @@ test_themed_icon (void) g_assert_cmpstr (names[0], ==, "first"); g_assert_cmpstr (names[1], ==, "testicon"); g_assert_cmpstr (names[2], ==, "last"); - g_assert_cmpuint (g_icon_hash (icon1), ==, 3193088045U); + g_assert_cmpuint (g_icon_hash (icon1), ==, 2400773466U); icon2 = g_themed_icon_new_from_names ((gchar**)names2, -1); g_assert (g_icon_equal (icon1, icon2)); @@ -299,11 +299,11 @@ test_emblemed_icon (void) emblem = emblems->data; g_assert (g_emblem_get_icon (emblem) == icon2); - g_assert (g_emblem_get_origin (emblem) == G_EMBLEM_ORIGIN_UNKNOWN); + g_assert (g_emblem_get_origin (emblem) == G_EMBLEM_ORIGIN_TAG); emblem = emblems->next->data; g_assert (g_emblem_get_icon (emblem) == icon2); - g_assert (g_emblem_get_origin (emblem) == G_EMBLEM_ORIGIN_TAG); + g_assert (g_emblem_get_origin (emblem) == G_EMBLEM_ORIGIN_UNKNOWN); g_object_unref (icon1); g_object_unref (icon2); From 57143e311d600d3d7bd1f3c901d257918fcdb381 Mon Sep 17 00:00:00 2001 From: Christian Persch Date: Fri, 26 Nov 2010 21:05:20 +0100 Subject: [PATCH 21/44] Inherit gettext-domain from When the doesn't have a 'gettext-domain' attribute, but the does, use that one. Bug #635640. --- gio/glib-compile-schemas.c | 4 +++- gio/tests/Makefile.am | 1 + gio/tests/gschema-compile.c | 4 +++- gio/tests/schema-tests/inherit-gettext-domain.gschema.xml | 8 ++++++++ 4 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 gio/tests/schema-tests/inherit-gettext-domain.gschema.xml diff --git a/gio/glib-compile-schemas.c b/gio/glib-compile-schemas.c index 7fe907c5e..a00e45de4 100644 --- a/gio/glib-compile-schemas.c +++ b/gio/glib-compile-schemas.c @@ -1228,7 +1228,9 @@ start_element (GMarkupParseContext *context, OPTIONAL | STRING, "gettext-domain", &gettext_domain, OPTIONAL | STRING, "extends", &extends, OPTIONAL | STRING, "list-of", &list_of)) - parse_state_start_schema (state, id, path, gettext_domain, + parse_state_start_schema (state, id, path, + gettext_domain ? gettext_domain + : state->schemalist_domain, extends, list_of, error); return; } diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am index ad2273a42..def7392a8 100644 --- a/gio/tests/Makefile.am +++ b/gio/tests/Makefile.am @@ -374,6 +374,7 @@ schema_tests = \ schema-tests/extending.gschema.xml \ schema-tests/from-docs.gschema.xml \ schema-tests/incomplete-list.gschema.xml \ + schema-tests/inherit-gettext-domain.gschema.xml \ schema-tests/invalid-path.gschema.xml \ schema-tests/key-in-list-indirect.gschema.xml \ schema-tests/key-in-list.gschema.xml \ diff --git a/gio/tests/gschema-compile.c b/gio/tests/gschema-compile.c index 1d261eb2b..caefb8975 100644 --- a/gio/tests/gschema-compile.c +++ b/gio/tests/gschema-compile.c @@ -117,9 +117,11 @@ static const SchemaTest tests[] = { { "flags-bad-default", NULL, "* * not in the specified flags type*" }, { "flags-more-than-one-bit", NULL, "*flags values must have at most 1 bit set*" }, { "flags-with-enum-attr", NULL, "* not (yet) defined*" }, - { "flags-with-enum-tag", NULL, "* not (yet) defined*" } + { "flags-with-enum-tag", NULL, "* not (yet) defined*" }, + { "inherit-gettext-domain", NULL, NULL } }; + int main (int argc, char *argv[]) { diff --git a/gio/tests/schema-tests/inherit-gettext-domain.gschema.xml b/gio/tests/schema-tests/inherit-gettext-domain.gschema.xml new file mode 100644 index 000000000..1f0ca89f7 --- /dev/null +++ b/gio/tests/schema-tests/inherit-gettext-domain.gschema.xml @@ -0,0 +1,8 @@ + + + + + 'value' + + + From bfbd7169a258ac9561f2d01755651046e13f462b Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 28 Nov 2010 17:14:49 -0500 Subject: [PATCH 22/44] GFileMonitor: Don't accept negative values for rate-limit Patch by Alksander Morgado, https://bugzilla.gnome.org/show_bug.cgi?id=635768 --- gio/gfilemonitor.c | 16 ++++++++-------- gio/gfilemonitor.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/gio/gfilemonitor.c b/gio/gfilemonitor.c index 38a0493bc..726cd628b 100644 --- a/gio/gfilemonitor.c +++ b/gio/gfilemonitor.c @@ -327,21 +327,21 @@ g_file_monitor_cancel (GFileMonitor* monitor) /** * g_file_monitor_set_rate_limit: * @monitor: a #GFileMonitor. - * @limit_msecs: a integer with the limit in milliseconds to - * poll for changes. + * @limit_msecs: a non-negative integer with the limit in milliseconds + * to poll for changes * * Sets the rate limit to which the @monitor will report - * consecutive change events to the same file. - * - **/ + * consecutive change events to the same file. + */ void g_file_monitor_set_rate_limit (GFileMonitor *monitor, - int limit_msecs) + gint limit_msecs) { GFileMonitorPrivate *priv; - + g_return_if_fail (G_IS_FILE_MONITOR (monitor)); - + g_return_if_fail (limit_msecs >= 0); + priv = monitor->priv; if (priv->rate_limit_msec != limit_msecs) { diff --git a/gio/gfilemonitor.h b/gio/gfilemonitor.h index cf6f6be41..8e27d22e0 100644 --- a/gio/gfilemonitor.h +++ b/gio/gfilemonitor.h @@ -81,7 +81,7 @@ GType g_file_monitor_get_type (void) G_GNUC_CONST; gboolean g_file_monitor_cancel (GFileMonitor *monitor); gboolean g_file_monitor_is_cancelled (GFileMonitor *monitor); void g_file_monitor_set_rate_limit (GFileMonitor *monitor, - int limit_msecs); + gint limit_msecs); /* For implementations */ From b4632e1c98e361cf4700f3e5dcc229a09a6237e4 Mon Sep 17 00:00:00 2001 From: Christian Persch Date: Fri, 26 Nov 2010 22:46:51 +0100 Subject: [PATCH 23/44] Fix the wrong-category schema test It's supposed to test a with a non-existent category, so make it actually check this! Bug #635882. --- gio/tests/gschema-compile.c | 2 +- gio/tests/schema-tests/wrong-category.gschema.xml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gio/tests/gschema-compile.c b/gio/tests/gschema-compile.c index caefb8975..2ffa85b56 100644 --- a/gio/tests/gschema-compile.c +++ b/gio/tests/gschema-compile.c @@ -46,7 +46,7 @@ static const SchemaTest tests[] = { { "no-default", NULL, "* is required in *" }, { "missing-quotes", NULL, "*unknown keyword*" }, { "incomplete-list", NULL, "*to follow array element*" }, - { "wrong-category", NULL, "*attribute 'l10n' invalid*" }, + { "wrong-category", NULL, "*unsupported l10n category*" }, { "bad-type", NULL, "*invalid GVariant type string*" }, { "overflow", NULL, "*out of range*" }, { "range-wrong-type", NULL, "* not allowed for keys of type*" }, diff --git a/gio/tests/schema-tests/wrong-category.gschema.xml b/gio/tests/schema-tests/wrong-category.gschema.xml index 5c1ec7923..c54824833 100644 --- a/gio/tests/schema-tests/wrong-category.gschema.xml +++ b/gio/tests/schema-tests/wrong-category.gschema.xml @@ -1,7 +1,7 @@ - - 'foo' + + 'foo' From 51894b7dd06a3b50654f9ce1fadff418d917aca1 Mon Sep 17 00:00:00 2001 From: Aleksander Morgado Date: Thu, 25 Nov 2010 18:38:33 +0100 Subject: [PATCH 24/44] Fixes GB#530786: GFileMonitor 'changed' signal underdocumented --- gio/gfilemonitor.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/gio/gfilemonitor.c b/gio/gfilemonitor.c index 726cd628b..f7a87b6f7 100644 --- a/gio/gfilemonitor.c +++ b/gio/gfilemonitor.c @@ -224,10 +224,16 @@ g_file_monitor_class_init (GFileMonitorClass *klass) * GFileMonitor::changed: * @monitor: a #GFileMonitor. * @file: a #GFile. - * @other_file: a #GFile. + * @other_file: a #GFile or #NULL. * @event_type: a #GFileMonitorEvent. - * - * Emitted when a file has been changed. + * + * Emitted when @file has been changed. + * + * If using #G_FILE_MONITOR_SEND_MOVED flag and @event_type is + * #G_FILE_MONITOR_SEND_MOVED, @file will be set to a #GFile containing the + * old path, and @other_file will be set to a #GFile containing the new path. + * + * In all the other cases, @other_file will be set to #NULL. **/ signals[CHANGED] = g_signal_new (I_("changed"), From 349f54756168b76913828136bc646c518c4f475f Mon Sep 17 00:00:00 2001 From: Jonas Holmberg Date: Fri, 24 Sep 2010 01:20:50 +0200 Subject: [PATCH 25/44] gobject: initialize memory in g_object_new_valist memset parameters array in g_object_new_valist to zeroes when expanding the array to avoid acces to uninitialized memory. --- gobject/gobject.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gobject/gobject.c b/gobject/gobject.c index e6f19da74..8b427fa62 100644 --- a/gobject/gobject.c +++ b/gobject/gobject.c @@ -1565,6 +1565,7 @@ g_object_new_valist (GType object_type, { n_alloced_params += 16; params = g_renew (GParameter, params, n_alloced_params); + memset (params + n_params, 0, 16 * (sizeof *params)); } params[n_params].name = name; G_VALUE_COLLECT_INIT (¶ms[n_params].value, pspec->value_type, From dec8323b4b301bb5aff006706b5739bb9c930fd8 Mon Sep 17 00:00:00 2001 From: Jonas Holmberg Date: Wed, 22 Sep 2010 23:02:05 +0200 Subject: [PATCH 26/44] gobject: added property test Added test for setting properties with g_object_new. --- gobject/tests/properties.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/gobject/tests/properties.c b/gobject/tests/properties.c index e2fef4c65..2a842cda0 100644 --- a/gobject/tests/properties.c +++ b/gobject/tests/properties.c @@ -207,6 +207,42 @@ properties_notify (void) g_object_unref (obj); } +static void +properties_construct (void) +{ + TestObject *obj; + gint val; + + g_test_bug ("630357"); + + /* more than 16 args triggers a realloc in g_object_new_valist() */ + obj = g_object_new (test_object_get_type (), + "foo", 1, + "foo", 2, + "foo", 3, + "foo", 4, + "foo", 5, + "foo", 6, + "foo", 7, + "foo", 8, + "foo", 9, + "foo", 10, + "foo", 11, + "foo", 12, + "foo", 13, + "foo", 14, + "foo", 15, + "foo", 16, + "foo", 17, + "foo", 18, + NULL); + + g_object_get (obj, "foo", &val, NULL); + g_assert (val == 18); + + g_object_unref (obj); +} + int main (int argc, char *argv[]) { @@ -217,6 +253,7 @@ main (int argc, char *argv[]) g_test_add_func ("/properties/install", properties_install); g_test_add_func ("/properties/notify", properties_notify); + g_test_add_func ("/properties/construct", properties_construct); return g_test_run (); } From 577ddbf30baf53d8e74cd81f0a2babf590e91c26 Mon Sep 17 00:00:00 2001 From: Matt Rajca Date: Sat, 13 Nov 2010 13:01:11 -0600 Subject: [PATCH 27/44] Fixed typo in public string in gsocks (630559) --- gio/gsocks5proxy.c | 2 +- po/ar.po | 2 +- po/be.po | 2 +- po/bg.po | 2 +- po/ca@valencia.po | 2 +- po/cs.po | 2 +- po/da.po | 2 +- po/de.po | 2 +- po/el.po | 2 +- po/en_GB.po | 2 +- po/es.po | 2 +- po/et.po | 2 +- po/eu.po | 2 +- po/fi.po | 2 +- po/fr.po | 2 +- po/gl.po | 2 +- po/he.po | 4 ++-- po/hu.po | 2 +- po/hy.po | 2 +- po/id.po | 2 +- po/it.po | 2 +- po/ja.po | 2 +- po/lt.po | 2 +- po/nb.po | 2 +- po/nl.po | 2 +- po/pa.po | 2 +- po/pl.po | 2 +- po/pt.po | 2 +- po/pt_BR.po | 2 +- po/ro.po | 2 +- po/sl.po | 2 +- po/sr.po | 2 +- po/sr@latin.po | 2 +- po/sv.po | 2 +- po/zh_CN.po | 2 +- po/zh_HK.po | 2 +- po/zh_TW.po | 2 +- 37 files changed, 38 insertions(+), 38 deletions(-) diff --git a/gio/gsocks5proxy.c b/gio/gsocks5proxy.c index 046f29031..07fc8ce2f 100644 --- a/gio/gsocks5proxy.c +++ b/gio/gsocks5proxy.c @@ -176,7 +176,7 @@ parse_nego_reply (const guint8 *data, case SOCKS5_AUTH_NO_ACCEPT: default: g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PROXY_AUTH_FAILED, - _("The SOCKSv5 require an authentication method that is not " + _("The SOCKSv5 proxy requires an authentication method that is not " "supported by GLib.")); return FALSE; break; diff --git a/po/ar.po b/po/ar.po index d4576fb5c..a12a17bc3 100644 --- a/po/ar.po +++ b/po/ar.po @@ -3205,7 +3205,7 @@ msgstr "" #: gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "" #: gio/gsocks5proxy.c:208 diff --git a/po/be.po b/po/be.po index b7f0a4eed..62654d6cc 100644 --- a/po/be.po +++ b/po/be.po @@ -3636,7 +3636,7 @@ msgstr "" #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "" #: ../gio/gsocks5proxy.c:208 diff --git a/po/bg.po b/po/bg.po index b0102b39b..54264929c 100644 --- a/po/bg.po +++ b/po/bg.po @@ -3411,7 +3411,7 @@ msgstr "Посредникът чрез SOCKSv5 изисква идентифи #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "" "Посредникът чрез SOCKSv5 изисква механизъм за идентификация, който не се " "поддържа от GLib." diff --git a/po/ca@valencia.po b/po/ca@valencia.po index a6ef9486d..be9eb8c5b 100644 --- a/po/ca@valencia.po +++ b/po/ca@valencia.po @@ -3351,7 +3351,7 @@ msgstr "" #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "" #: ../gio/gsocks5proxy.c:208 diff --git a/po/cs.po b/po/cs.po index 27527b626..bd795c40d 100644 --- a/po/cs.po +++ b/po/cs.po @@ -3382,7 +3382,7 @@ msgstr "SOCKSv5 proxy vyžaduje ověření." #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "SOCKSv5 vyžaduje metodu ověření nepodporovanou v GLib." #: ../gio/gsocks5proxy.c:208 diff --git a/po/da.po b/po/da.po index e7d228fc0..f4446c8a8 100644 --- a/po/da.po +++ b/po/da.po @@ -3384,7 +3384,7 @@ msgstr "SOCKSv5-proxy'en kræver godkendelse." #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "SOCKSv5 kræver en godkendelsesmetode, der ikke understøttes af GLib." #: ../gio/gsocks5proxy.c:208 diff --git a/po/de.po b/po/de.po index 2a2a3ffd2..58f96deb9 100644 --- a/po/de.po +++ b/po/de.po @@ -3457,7 +3457,7 @@ msgstr "Der SOCKSv5-Proxy erfordert Legitimierung." #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "" "Der SOCKSv5 erfordert eine Legitimierungsmethode, die durch GLib nicht " "unterstützt wird." diff --git a/po/el.po b/po/el.po index 2260f9e95..1a20c0ae5 100644 --- a/po/el.po +++ b/po/el.po @@ -3529,7 +3529,7 @@ msgstr "Το SOCKSv5 proxy απαιτεί επικύρωση." #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "" "Το SOCKSv5 απαιτεί μια μέθοδο επικύρωσης που δεν υποστηρίζεται από GLib." diff --git a/po/en_GB.po b/po/en_GB.po index 3d80bc76e..b1c22b583 100644 --- a/po/en_GB.po +++ b/po/en_GB.po @@ -3351,7 +3351,7 @@ msgstr "The SOCKSv5 proxy requires authentication." #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "" "The SOCKSv5 proxy requires an authentication method that is not supported by " "GLib." diff --git a/po/es.po b/po/es.po index 54eb4f875..186ce060e 100644 --- a/po/es.po +++ b/po/es.po @@ -3589,7 +3589,7 @@ msgstr "El servidor proxy SOCKSv5 requiere autenticación." #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "" "El servidor SOCKSv5 requiere un método de autenticación que GLib no soporta." diff --git a/po/et.po b/po/et.po index d05ca2fd8..dded40fab 100644 --- a/po/et.po +++ b/po/et.po @@ -2511,7 +2511,7 @@ msgid "The SOCKSv5 proxy requires authentication." msgstr "" msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "" #, c-format diff --git a/po/eu.po b/po/eu.po index bc000419f..4835fc78f 100644 --- a/po/eu.po +++ b/po/eu.po @@ -3166,7 +3166,7 @@ msgstr "SOCKSv5 proxy-ak autentifikazioa eskatzen du." #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "" "OCKSv5-ek autentifikatzeko metodo bat eskatzen du (Glib-ek onartzen ez " "duena)." diff --git a/po/fi.po b/po/fi.po index 3ed7b7194..5bfd5b306 100644 --- a/po/fi.po +++ b/po/fi.po @@ -3259,7 +3259,7 @@ msgstr "" #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "" #: ../gio/gsocks5proxy.c:208 diff --git a/po/fr.po b/po/fr.po index c7d61d7bd..5355e2562 100644 --- a/po/fr.po +++ b/po/fr.po @@ -3509,7 +3509,7 @@ msgstr "Le serveur mandataire SOCKSv5 nécessite une authentification." #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "" "Le protocole SOCKSv5 nécessite une méthode d'authentification qui n'est pas " "prise en charge par GLib." diff --git a/po/gl.po b/po/gl.po index ed86a2023..fd3824e7b 100644 --- a/po/gl.po +++ b/po/gl.po @@ -3566,7 +3566,7 @@ msgstr "O proxy SOCKSv5 require autenticación." #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "" "SOCKSv5 require un método de autenticación que non é compatíbel con GLib." diff --git a/po/he.po b/po/he.po index e3f3dbd2d..a8399c421 100644 --- a/po/he.po +++ b/po/he.po @@ -3465,9 +3465,9 @@ msgstr "The SOCKSv5 proxy requires authentication." #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." #: ../gio/gsocks5proxy.c:208 #, c-format diff --git a/po/hu.po b/po/hu.po index 684a0f433..06e6f7f1f 100644 --- a/po/hu.po +++ b/po/hu.po @@ -3363,7 +3363,7 @@ msgid "The SOCKSv5 proxy requires authentication." msgstr "A SOCKSv5 proxy hitelesítést igényel." #: ../gio/gsocks5proxy.c:179 -msgid "The SOCKSv5 require an authentication method that is not supported by GLib." +msgid "The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "A SOCKSv5 a GLib által nem támogatott hitelesítési módszert igényel." #: ../gio/gsocks5proxy.c:208 diff --git a/po/hy.po b/po/hy.po index a6945b33c..3b9e37986 100644 --- a/po/hy.po +++ b/po/hy.po @@ -3119,7 +3119,7 @@ msgstr "SOCKSv5 պրոքսին պահանջում է վավերացում" #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "SOCKSv5 պահանջում է վավերացման մեթոդ, որը չի աջակցվում GLib-ի կողմից։" #: ../gio/gsocks5proxy.c:208 diff --git a/po/id.po b/po/id.po index 30c2a47e9..be6451616 100644 --- a/po/id.po +++ b/po/id.po @@ -3287,7 +3287,7 @@ msgstr "Proksi SOCKv5 memerlukan otentikasi." #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "SOCKSv5 memerlukan metoda otentikasi yang tidak didukung oleh GLib." #: ../gio/gsocks5proxy.c:208 diff --git a/po/it.po b/po/it.po index 15c75ec78..5da49700b 100644 --- a/po/it.po +++ b/po/it.po @@ -3493,7 +3493,7 @@ msgstr "" #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "" #: ../gio/gsocks5proxy.c:208 diff --git a/po/ja.po b/po/ja.po index 2464a3925..6cd8e0395 100644 --- a/po/ja.po +++ b/po/ja.po @@ -3361,7 +3361,7 @@ msgstr "" #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "" #: ../gio/gsocks5proxy.c:208 diff --git a/po/lt.po b/po/lt.po index 875c1ca38..60ab2b946 100644 --- a/po/lt.po +++ b/po/lt.po @@ -3401,7 +3401,7 @@ msgstr "SOCKSv5 proxy reikalauja tapatybės patvirtinimo." #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "" "SOCKSv5 reikalauja tapatybės patvirtinimo metodo, kurio GLib nepalaiko." diff --git a/po/nb.po b/po/nb.po index f73243813..88eaba266 100644 --- a/po/nb.po +++ b/po/nb.po @@ -3387,7 +3387,7 @@ msgstr "SOCSv5-proxy krever autentisering." #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "" #: ../gio/gsocks5proxy.c:208 diff --git a/po/nl.po b/po/nl.po index f64df8662..0951be0d5 100644 --- a/po/nl.po +++ b/po/nl.po @@ -3395,7 +3395,7 @@ msgstr "De SOCKSv5-proxy vereist authenticatie." #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "" #: ../gio/gsocks5proxy.c:208 diff --git a/po/pa.po b/po/pa.po index 0b1253d3c..a0044ce91 100644 --- a/po/pa.po +++ b/po/pa.po @@ -3409,7 +3409,7 @@ msgid "The SOCKSv5 proxy requires authentication." msgstr "SOCKSv5 ਪਰਾਕਸੀ ਲਈ ਪਰਮਾਣਿਕਤਾ ਦੀ ਲੋੜ ਹੈ।" #: ../gio/gsocks5proxy.c:179 -msgid "The SOCKSv5 require an authentication method that is not supported by GLib." +msgid "The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "SOCKSv5 ਲਈ ਅਜਿਹੇ ਪਰਮਾਣਿਕਤਾ ਢੰਗ ਦੀ ਲੋੜ ਹੈ, ਜੋ ਕਿ GLib ਵਲੋਂ ਸਹਾਇਕ ਨਹੀਂ ਹੈ।" #: ../gio/gsocks5proxy.c:208 diff --git a/po/pl.po b/po/pl.po index 8ffb30bee..4d2c7c15e 100644 --- a/po/pl.po +++ b/po/pl.po @@ -3373,7 +3373,7 @@ msgid "The SOCKSv5 proxy requires authentication." msgstr "Pośrednik SOCKSv5 wymaga uwierzytelnienia." #: ../gio/gsocks5proxy.c:179 -msgid "The SOCKSv5 require an authentication method that is not supported by GLib." +msgid "The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "SOCKSv5 wymaga metody uwierzytelnienia nieobsługiwaną przez bibliotekę GLib." #: ../gio/gsocks5proxy.c:208 diff --git a/po/pt.po b/po/pt.po index 15710dec9..1fedb3754 100644 --- a/po/pt.po +++ b/po/pt.po @@ -3360,7 +3360,7 @@ msgstr "A proxy SOCKSv5 requer autenticação." #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "" "O SOCKSv5 requer um método de autenticação que não é suportado pelo GLib." diff --git a/po/pt_BR.po b/po/pt_BR.po index 958db3780..10115a5dc 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -3391,7 +3391,7 @@ msgstr "O proxy SOCKSv5 requer autenticação." #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "O SOCKSv5 requer um método de autenticação sem suporte pelo GLib." #: ../gio/gsocks5proxy.c:208 diff --git a/po/ro.po b/po/ro.po index fde75472f..e1aa1722f 100644 --- a/po/ro.po +++ b/po/ro.po @@ -3374,7 +3374,7 @@ msgstr "Proxy-ul SOCKSv5 necesită autentificare." #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "" "SOCKSv5 necesită o metodă de autentificare ce nu este acceptată de GLib." diff --git a/po/sl.po b/po/sl.po index 10b86d7f4..5e936a4ee 100644 --- a/po/sl.po +++ b/po/sl.po @@ -3332,7 +3332,7 @@ msgid "The SOCKSv5 proxy requires authentication." msgstr "SOCKSv5 posredniški strežnik zahteva overitev." #: ../gio/gsocks5proxy.c:179 -msgid "The SOCKSv5 require an authentication method that is not supported by GLib." +msgid "The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "SOCKSv5 zahteva overitveni način, ki ni podprta v GLib." #: ../gio/gsocks5proxy.c:208 diff --git a/po/sr.po b/po/sr.po index 21e012b66..341a4ff5b 100644 --- a/po/sr.po +++ b/po/sr.po @@ -3321,7 +3321,7 @@ msgstr "The SOCKSv5 прокси захтева пријављивање." #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "Овај SOCKSv5 захтева начин пријављивања који GLib не подржава." #: ../gio/gsocks5proxy.c:208 diff --git a/po/sr@latin.po b/po/sr@latin.po index 7b333adde..b57da2d73 100644 --- a/po/sr@latin.po +++ b/po/sr@latin.po @@ -3321,7 +3321,7 @@ msgstr "The SOCKSv5 proksi zahteva prijavljivanje." #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "Ovaj SOCKSv5 zahteva način prijavljivanja koji GLib ne podržava." #: ../gio/gsocks5proxy.c:208 diff --git a/po/sv.po b/po/sv.po index 15ee73a26..bd2d9ad6f 100644 --- a/po/sv.po +++ b/po/sv.po @@ -3090,7 +3090,7 @@ msgid "The SOCKSv5 proxy requires authentication." msgstr "SOCKSv5-proxyservern kräver autentisering." #: ../gio/gsocks5proxy.c:179 -msgid "The SOCKSv5 require an authentication method that is not supported by GLib." +msgid "The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "SOCKSv5 kräver en autentiseringsmetod som inte stöds av GLib." #: ../gio/gsocks5proxy.c:208 diff --git a/po/zh_CN.po b/po/zh_CN.po index ca5a9d6a8..e11747549 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -3181,7 +3181,7 @@ msgstr "SOCKSv5 代理服务器需要认证。" #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "此 SOCKSv5 连接需要一种 GLib 未支持的认证方法。" #: ../gio/gsocks5proxy.c:208 diff --git a/po/zh_HK.po b/po/zh_HK.po index cfac12e51..c4c386598 100644 --- a/po/zh_HK.po +++ b/po/zh_HK.po @@ -3195,7 +3195,7 @@ msgstr "SOCKv5 代理伺服器要求驗證。" #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "SOCKSv5 需要的驗證方式尚未被 GLib 支援。" #: ../gio/gsocks5proxy.c:208 diff --git a/po/zh_TW.po b/po/zh_TW.po index 724fd6924..349a69208 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -3217,7 +3217,7 @@ msgstr "SOCKv5 代理伺服器要求驗證。" #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 require an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." msgstr "SOCKSv5 需要的驗證方式尚未被 GLib 支援。" #: ../gio/gsocks5proxy.c:208 From 4817dae0bb2dfe9d0b575356ddf43b2f3ecd41f5 Mon Sep 17 00:00:00 2001 From: Matt Rajca Date: Sat, 13 Nov 2010 10:01:34 -0600 Subject: [PATCH 28/44] Removed mention of inexistent GNOME 2.0 porting guide --- docs/reference/glib/changes.sgml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/docs/reference/glib/changes.sgml b/docs/reference/glib/changes.sgml index c64ffc2f8..51fcab4fd 100644 --- a/docs/reference/glib/changes.sgml +++ b/docs/reference/glib/changes.sgml @@ -56,14 +56,6 @@ with Glib-2.0 that you need to reproduce exactly. Incompatible changes from 1.2 to 2.0 - -The GNOME 2.0 -porting guide on http://developer.gnome.org -has some more detailed discussion of porting from 1.2 to 2.0. -See the section on GLib. - - From 1f044a503a9b1b021da970ab1bdfe203547798c1 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 28 Nov 2010 22:11:57 -0500 Subject: [PATCH 29/44] Remove nonexisting type --- docs/reference/gio/gio.types | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/reference/gio/gio.types b/docs/reference/gio/gio.types index 4b3afe0e7..76eb7e020 100644 --- a/docs/reference/gio/gio.types +++ b/docs/reference/gio/gio.types @@ -77,7 +77,6 @@ g_password_save_get_type g_periodic_get_type g_permission_get_type g_pollable_input_stream_get_type -g_pollable_io_stream_get_type g_pollable_output_stream_get_type g_proxy_address_enumerator_get_type g_proxy_address_get_type From eed36d38d155898a13961ef9fbb98d09049f331f Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 28 Nov 2010 23:55:43 -0500 Subject: [PATCH 30/44] Various doc tweaks --- docs/reference/gio/gio-docs.xml | 8 +-- docs/reference/gio/gio-sections.txt | 3 +- gio/gaction.c | 2 +- gio/gactiongroup.c | 2 +- gio/gapplicationcommandline.c | 3 +- gio/gdesktopappinfo.c | 1 + gio/gperiodic.c | 91 ++++++++++++++++++----------- gio/gpermission.c | 2 +- gio/gpollableinputstream.c | 9 ++- gio/gpollableinputstream.h | 2 +- gio/gpollableoutputstream.c | 9 ++- gio/gsettings.c | 2 +- gio/gsettingsbackend.c | 2 +- gio/gsimpleaction.c | 2 +- gio/gsimpleactiongroup.c | 2 +- gio/gsimplepermission.c | 2 +- gio/gtcpconnection.c | 2 +- gio/gtcpwrapperconnection.c | 3 +- gio/gtlsbackend.c | 2 +- gio/gtlscertificate.c | 2 +- gio/gtlsconnection.c | 7 +++ 21 files changed, 91 insertions(+), 67 deletions(-) diff --git a/docs/reference/gio/gio-docs.xml b/docs/reference/gio/gio-docs.xml index 4676bc02a..ce756433e 100644 --- a/docs/reference/gio/gio-docs.xml +++ b/docs/reference/gio/gio-docs.xml @@ -32,6 +32,10 @@ File System Monitoring
+ + File-related Utilities + + Asynchronous I/O @@ -161,10 +165,6 @@ - - Utilities - - Settings diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt index 3574e1ead..b49d501b7 100644 --- a/docs/reference/gio/gio-sections.txt +++ b/docs/reference/gio/gio-sections.txt @@ -3010,7 +3010,7 @@ GTlsCertificateFlags
gtlsbackend -GTlsBackend</FILE> +<TITLE>GTlsBackend G_TLS_BACKEND_EXTENSION_POINT_NAME GTlsBackend GTlsBackendInterface @@ -3033,7 +3033,6 @@ g_tls_backend_get_type gtlscertificate GTlsCertificate GTlsCertificate -g_tls_certificate_new g_tls_certificate_new_from_pem g_tls_certificate_new_from_file g_tls_certificate_new_from_files diff --git a/gio/gaction.c b/gio/gaction.c index 1d1d16e34..6c2ee1db5 100644 --- a/gio/gaction.c +++ b/gio/gaction.c @@ -28,7 +28,7 @@ G_DEFINE_INTERFACE (GAction, g_action, G_TYPE_OBJECT) /** * SECTION:gaction * @title: GAction - * @short_description: an action + * @short_description: An action * * #GAction represents a single named action. * diff --git a/gio/gactiongroup.c b/gio/gactiongroup.c index 5efb2096c..735f016be 100644 --- a/gio/gactiongroup.c +++ b/gio/gactiongroup.c @@ -28,7 +28,7 @@ /** * SECTION:gactiongroup * @title: GActionGroup - * @short_description: a group of actions + * @short_description: A group of actions * * #GActionGroup represents a group of actions. * diff --git a/gio/gapplicationcommandline.c b/gio/gapplicationcommandline.c index 5931f57d7..c52398c3d 100644 --- a/gio/gapplicationcommandline.c +++ b/gio/gapplicationcommandline.c @@ -33,8 +33,7 @@ G_DEFINE_TYPE (GApplicationCommandLine, g_application_command_line, G_TYPE_OBJEC /** * SECTION:gapplicationcommandline * @title: GApplicationCommandLine - * @short_description: A class representing a command-line invocation of - * an application + * @short_description: A command-line invocation of an application * @see_also: #GApplication * * #GApplicationCommandLine represents a command-line invocation of diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c index ce3c8c9ac..a7648c984 100644 --- a/gio/gdesktopappinfo.c +++ b/gio/gdesktopappinfo.c @@ -48,6 +48,7 @@ /** * SECTION:gdesktopappinfo + * @title: GDesktopAppInfo * @short_description: Application information from desktop files * @include: gio/gdesktopappinfo.h * diff --git a/gio/gperiodic.c b/gio/gperiodic.c index cf8482105..af7a2d583 100644 --- a/gio/gperiodic.c +++ b/gio/gperiodic.c @@ -34,7 +34,7 @@ * of times per second and is capable of being put into synch with an * external time source. * - * A number of #GPeriodicTickFuncs are registered with + * A number of #GPeriodicTickFuncs are registered with * g_periodic_add() and are called each time the clock "ticks". * * The tick functions can report "damage" (ie: updates that need to be @@ -262,7 +262,7 @@ g_periodic_prepare (GSource *source, /* We need to run. */ { gint64 remaining; - + remaining = periodic->priv->last_run + 1000000 * (1 + periodic->priv->skip_frames) - g_periodic_get_microticks (periodic); @@ -354,8 +354,10 @@ g_periodic_dispatch (GSource *source, } static void -g_periodic_get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) +g_periodic_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) { GPeriodic *periodic = G_PERIODIC (object); @@ -379,8 +381,10 @@ g_periodic_get_property (GObject *object, guint prop_id, } static void -g_periodic_set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) +g_periodic_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) { GPeriodic *periodic = G_PERIODIC (object); @@ -445,11 +449,25 @@ g_periodic_class_init (GPeriodicClass *class) object_class->set_property = g_periodic_set_property; object_class->finalize = g_periodic_finalize; + /** + * GPeriodic::tick + * @periodic: the #GPeriodic on which the signal was emitted + * @timestamp: the timestamp at the time of the tick + * + * The ::tick signal gets emitted whenever the clock "fires". + */ g_periodic_tick = g_signal_new ("tick", G_TYPE_PERIODIC, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(GPeriodicClass, tick), NULL, NULL, _gio_marshal_VOID__INT64, G_TYPE_NONE, 1, G_TYPE_INT64); + + /** + * GPeriodic::repair: + * @periodic: the #GPeriodic on which the signal was emitted + * + * The ::repair signal gets emitted to start the "repair" phase. + */ g_periodic_repair = g_signal_new ("repair", G_TYPE_PERIODIC, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GPeriodicClass, repair), @@ -484,13 +502,14 @@ g_periodic_class_init (GPeriodicClass *class) * Temporarily blocks @periodic from running in order to bring it in * synch with an external time source. * - * This function must be called from a handler of the "repair" signal. + * This function must be called from a handler of the #GPeriodic::repair + * signal. * - * If this function is called, emission of the tick signal will be - * suspended until g_periodic_unblock() is called an equal number of - * times. Once that happens, the "tick" signal will run immediately and - * future "tick" signals will be emitted relative to the time at which - * the last call to g_periodic_unblock() occured. + * If this function is called, emission of the #GPeriodic::tick signal + * will be suspended until g_periodic_unblock() is called an equal number + * of times. Once that happens, the ::tick signal will run immediately + * and future ::tick signals will be emitted relative to the time at + * which the last call to g_periodic_unblock() occured. * * Since: 2.28 **/ @@ -510,9 +529,9 @@ g_periodic_block (GPeriodic *periodic) * * Reverses the effect of a previous call to g_periodic_block(). * - * If this call removes the last block, the tick signal is immediately - * run. The repair signal may also be run if the clock is marked as - * damaged. + * If this call removes the last block, the ::tick signal is + * immediately run. The ::repair signal may also be run if the clock + * is marked as damaged. * * @unblock_time is the monotonic time, as per g_get_monotonic_time(), * at which the event causing the unblock occured. @@ -545,20 +564,21 @@ g_periodic_unblock (GPeriodic *periodic, * @user_data: data for @callback * @notify: for freeing @user_data when it is no longer needed * - * Request periodic calls to @callback to start. The periodicity of the - * calls is determined by the 'hz' property. + * Request periodic calls to @callback to start. The periodicity of + * the calls is determined by the #GPeriodic:hz property. * - * This function may not be called from a handler of the repair signal, - * but it is perfectly reasonable to call it from a handler of the tick - * signal. + * This function may not be called from a handler of the ::repair + * signal, but it is perfectly reasonable to call it from a handler + * of the ::tick signal. * - * The callback may be cancelled later by using g_periodic_remove() on - * the return value of this function. + * The callback may be cancelled later by using g_periodic_remove() + * on the return value of this function. * * Returns: a non-zero tag identifying this callback * * Since: 2.28 **/ + /** * GPeriodicTickFunc: * @periodic: the #GPeriodic clock that is ticking @@ -568,8 +588,8 @@ g_periodic_unblock (GPeriodic *periodic, * The signature of the callback function that is called when the * #GPeriodic clock ticks. * - * The @timestamp parameter is equal for all callbacks called during a - * particular tick on a given clock. + * The @timestamp parameter is equal for all callbacks called during + * a particular tick on a given clock. * * Since: 2.28 **/ @@ -605,9 +625,9 @@ g_periodic_add (GPeriodic *periodic, * * @tag is the ID returned by that function. * - * This function may not be called from a handler of the repair signal, - * but it is perfectly reasonable to call it from a handler of the tick - * signal. + * This function may not be called from a handler of the ::repair + * signal, but it is perfectly reasonable to call it from a handler + * of the ::tick signal. * * Since: 2.28 **/ @@ -626,7 +646,7 @@ g_periodic_remove (GPeriodic *periodic, if (tick->id == tag) { - /* do this first incase the destroy notify re-enters */ + /* do this first, in case the destroy notify re-enters */ *iter = g_slist_remove (*iter, tick); if (tick->notify) @@ -644,8 +664,8 @@ g_periodic_remove (GPeriodic *periodic, * g_periodic_damaged: * @periodic: a #GPeriodic clock * - * Report damage and schedule the "repair" signal to be emitted during - * the next repair phase. + * Report damage and schedule the ::repair signal to be emitted + * during the next repair phase. * * You may not call this function during the repair phase. * @@ -666,7 +686,7 @@ g_periodic_damaged (GPeriodic *periodic) * * Gets the frequency of the clock. * - * Returns: the frquency of the clock, in Hz + * Returns: the frequency of the clock, in Hz * * Since: 2.28 **/ @@ -713,13 +733,14 @@ g_periodic_get_low_priority (GPeriodic *periodic) /** * g_periodic_new: * @hz: the frequency of the new clock in Hz (between 1 and 120) - * @priority: the #GSource priority to run at + * @high_priority: the #GSource priority to run at + * @low_priority: ignore tasks below this priority * * Creates a new #GPeriodic clock. * - * The created clock is attached to the thread-default main context in - * effect at the time of the call to this function. See - * g_main_context_push_thread_default() for more information. + * The created clock is attached to the thread-default main context + * in effect at the time of the call to this function. + * See g_main_context_push_thread_default() for more information. * * Due to the fact that #GMainContext is only accurate to the nearest * millisecond, the frequency can not meaningfully get too close to diff --git a/gio/gpermission.c b/gio/gpermission.c index a6963505a..97a4fd949 100644 --- a/gio/gpermission.c +++ b/gio/gpermission.c @@ -28,7 +28,7 @@ /** * SECTION:gpermission * @title: GPermission - * @short_description: an object representing the permission to perform + * @short_description: An object representing the permission to perform * a certain action * * A #GPermission represents the status of the caller's permission to diff --git a/gio/gpollableinputstream.c b/gio/gpollableinputstream.c index 19946c666..d6937d835 100644 --- a/gio/gpollableinputstream.c +++ b/gio/gpollableinputstream.c @@ -35,8 +35,8 @@ * * #GPollableInputStream is implemented by #GInputStreams that * can be polled for readiness to read. This can be used when - * interfacing with a non-gio API that expects - * unix-file-descriptor-style asynchronous I/O rather than gio-style. + * interfacing with a non-GIO API that expects + * UNIX-file-descriptor-style asynchronous I/O rather than GIO-style. * * Since: 2.28 */ @@ -125,9 +125,8 @@ g_pollable_input_stream_is_readable (GPollableInputStream *stream) * * As with g_pollable_input_stream_is_readable(), it is possible that * the stream may not actually be readable even after the source - * triggers, so you should use - * g_pollable_input_stream_read_nonblocking() rather than - * g_input_stream_read() from the callback. + * triggers, so you should use g_pollable_input_stream_read_nonblocking() + * rather than g_input_stream_read() from the callback. * * Returns: a new #GSource * diff --git a/gio/gpollableinputstream.h b/gio/gpollableinputstream.h index 5def93ba8..3b57460fd 100644 --- a/gio/gpollableinputstream.h +++ b/gio/gpollableinputstream.h @@ -92,7 +92,7 @@ gssize g_pollable_input_stream_read_nonblocking (GPollableInputStream *stream GError **error); /* Helper method for stream implementations */ -GSource *g_pollable_source_new (GObject *stream); +GSource *g_pollable_source_new (GObject *pollable_stream); G_END_DECLS diff --git a/gio/gpollableoutputstream.c b/gio/gpollableoutputstream.c index cb9138aad..b4efb3fe3 100644 --- a/gio/gpollableoutputstream.c +++ b/gio/gpollableoutputstream.c @@ -36,8 +36,8 @@ * * #GPollableOutputStream is implemented by #GOutputStreams that * can be polled for readiness to write. This can be used when - * interfacing with a non-gio API that expects - * unix-file-descriptor-style asynchronous I/O rather than gio-style. + * interfacing with a non-GIO API that expects + * UNIX-file-descriptor-style asynchronous I/O rather than GIO-style. * * Since: 2.28 */ @@ -126,9 +126,8 @@ g_pollable_output_stream_is_writable (GPollableOutputStream *stream) * * As with g_pollable_output_stream_is_writable(), it is possible that * the stream may not actually be writable even after the source - * triggers, so you should use - * g_pollable_output_stream_write_nonblocking() rather than - * g_output_stream_write() from the callback. + * triggers, so you should use g_pollable_output_stream_write_nonblocking() + * rather than g_output_stream_write() from the callback. * * Returns: a new #GSource * diff --git a/gio/gsettings.c b/gio/gsettings.c index 724d67f6e..8c3bd72d2 100644 --- a/gio/gsettings.c +++ b/gio/gsettings.c @@ -42,7 +42,7 @@ /** * SECTION:gsettings - * @short_description: a high-level API for application settings + * @short_description: High-level API for application settings * * The #GSettings class provides a convenient API for storing and retrieving * application settings. diff --git a/gio/gsettingsbackend.c b/gio/gsettingsbackend.c index 475d05540..bd2fa2e82 100644 --- a/gio/gsettingsbackend.c +++ b/gio/gsettingsbackend.c @@ -49,7 +49,7 @@ struct _GSettingsBackendPrivate /** * SECTION:gsettingsbackend * @title: GSettingsBackend - * @short_description: an interface for settings backend implementations + * @short_description: Interface for settings backend implementations * @include: gio/gsettingsbackend.h * @see_also: #GSettings, #GIOExtensionPoint * diff --git a/gio/gsimpleaction.c b/gio/gsimpleaction.c index e0eebaa2a..388ead3de 100644 --- a/gio/gsimpleaction.c +++ b/gio/gsimpleaction.c @@ -33,7 +33,7 @@ G_DEFINE_TYPE_WITH_CODE (GSimpleAction, g_simple_action, G_TYPE_OBJECT, /** * SECTION:gsimpleaction * @title: GSimpleAction - * @short_description: a simple GSimpleAction + * @short_description: A simple GSimpleAction * * A #GSimpleAction is the obvious simple implementation of the #GSimpleAction * interface. This is the easiest way to create an action for purposes of diff --git a/gio/gsimpleactiongroup.c b/gio/gsimpleactiongroup.c index 940a08142..ecc1dceae 100644 --- a/gio/gsimpleactiongroup.c +++ b/gio/gsimpleactiongroup.c @@ -25,7 +25,7 @@ /** * SECTION:gsimpleactiongroup * @title: GSimpleActionGroup - * @short_description: a simple GActionGroup implementation + * @short_description: A simple GActionGroup implementation * * #GSimpleActionGroup is a hash table filled with #GAction objects, * implementing the #GActionGroup interface. diff --git a/gio/gsimplepermission.c b/gio/gsimplepermission.c index 54cc00e21..c932c2ca3 100644 --- a/gio/gsimplepermission.c +++ b/gio/gsimplepermission.c @@ -28,7 +28,7 @@ /** * SECTION:gsimplepermission * @title: GSimplePermission - * @short_description: a GPermission that doesn't change value + * @short_description: A GPermission that doesn't change value * * #GSimplePermission is a trivial implementation of #GPermission that * represents a permission that is either always or never allowed. The diff --git a/gio/gtcpconnection.c b/gio/gtcpconnection.c index 08364c180..f667862df 100644 --- a/gio/gtcpconnection.c +++ b/gio/gtcpconnection.c @@ -13,7 +13,7 @@ /** * SECTION: gtcpconnection * @title: GTcpConnection - * @short_description: a TCP GSocketConnection + * @short_description: A TCP GSocketConnection * @see_also: #GSocketConnection. * * This is the subclass of #GSocketConnection that is created diff --git a/gio/gtcpwrapperconnection.c b/gio/gtcpwrapperconnection.c index 47970ad97..7c2ff15ce 100644 --- a/gio/gtcpwrapperconnection.c +++ b/gio/gtcpwrapperconnection.c @@ -23,8 +23,7 @@ /** * SECTION: gtcpwrapperconnection * @title: GTcpWrapperConnection - * @short_description: a wrapper for non-#GSocketConnection-based - * #GIOStreams that are nonetheless based on a #GSocket + * @short_description: wrapper for non-GSocketConnection-based, GSocket-based GIOStreams * @see_also: #GSocketConnection. * * A #GTcpWrapperConnection can be used to wrap a #GIOStream that is diff --git a/gio/gtlsbackend.c b/gio/gtlsbackend.c index 6c93c48a7..64a979461 100644 --- a/gio/gtlsbackend.c +++ b/gio/gtlsbackend.c @@ -29,7 +29,7 @@ /** * SECTION:gtls * @title: TLS Overview - * @short_description: TLS (aka SSL) support for #GSocketConnection + * @short_description: TLS (aka SSL) support for GSocketConnection * @include: gio/gio.h * * #GTlsConnection and related classes provide TLS (Transport Layer diff --git a/gio/gtlscertificate.c b/gio/gtlscertificate.c index 876049cb9..be1f9af47 100644 --- a/gio/gtlscertificate.c +++ b/gio/gtlscertificate.c @@ -31,7 +31,7 @@ /** * SECTION: gtlscertificate * @title: GTlsCertificate - * @short_description: a TLS certificate + * @short_description: TLS certificate * @see_also: #GTlsConnection * * A certificate used for TLS authentication and encryption. diff --git a/gio/gtlsconnection.c b/gio/gtlsconnection.c index e9e4250ed..e55f6f59c 100644 --- a/gio/gtlsconnection.c +++ b/gio/gtlsconnection.c @@ -666,6 +666,8 @@ g_tls_connection_certificate_accumulator (GSignalInvocationHint *ihint, * Used by #GTlsConnection implementations to emit the * #GTlsConnection::need-certificate signal. * + * Returns: a new #GTlsCertificate + * * Since: 2.28 */ GTlsCertificate * @@ -681,10 +683,15 @@ g_tls_connection_emit_need_certificate (GTlsConnection *conn) /** * g_tls_connection_emit_accept_certificate: * @conn: a #GTlsConnection + * @peer_cert: the peer's #GTlsCertificate + * @errors: the problems with @peer_cert * * Used by #GTlsConnection implementations to emit the * #GTlsConnection::accept-certificate signal. * + * Return value: %TRUE if one of the signal handlers has returned + * %TRUE to accept @peer_cert + * * Since: 2.28 */ gboolean From 02978fff17bcff0bf0135859114d6a06463f4e8d Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 29 Nov 2010 01:16:02 -0500 Subject: [PATCH 31/44] Update NEWS --- NEWS | 39 +++++++++++++++++++++++++++++++++++++++ glib/gutils.c | 8 +++++--- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index 3d9bd4b80..837160cbb 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,42 @@ +Overview of Changes from GLib 2.27.3 to 2.27.4 +============================================== + +* GIO + - Mounts are treated as hidden if they have a path element + that starts with a dot + - GAppInfo gained API to differentiate between recommended + and fallback mime handlers + - g_cancellable_create_source: creates a GSource that triggers + when the GCancellable is canceled + - GPollableInput/OutputStream: Interfaces for pollable streams + - TLS support has landed, with an extension point that is + implemented in glib-networking + +* GLib + - Mainloop sources can now have 'child sources' + - g_get_runtime_dir: New function to return the XDG_RUNTIME_DIR + +* Bugs fixed: + 530786 GFileMonitor "changed" signal underdocumented + 588189 TLS support for GSocket* + 630357 g_object_new_valist uses uninitialized memory + 630559 typo in public string in gsocks: 'The SOCKSv5 require... + 632445 Documentation refers to removed GNOME 2.0 porting guide + 634239 Child GSources + 634241 Add pollable input/output streams + 634504 allow passing a NULL emblem to g_emblemed_icon_new() + 634613 unsufficient g_get_user_runtime_dir() documentation + 635640 schema should inherit gettext-domain from schemalist + 635768 Protect g_file_monitor_set_rate_limit() against negative... + 635882 Fix the wrong-category schema test + +* Updated translations: + Galician + Italian + Norwegian bokmål + Uyghur + + Overview of Changes from GLib 2.27.2 to 2.27.3 ============================================== diff --git a/glib/gutils.c b/glib/gutils.c index 318eb3457..73165ba14 100644 --- a/glib/gutils.c +++ b/glib/gutils.c @@ -2299,9 +2299,9 @@ g_get_user_cache_dir (void) * On UNIX platforms this is determined using the mechanisms described in * the * XDG Base Directory Specification. This is the directory - * specified in the XDG_RUNTIME_DIR environment variable. In the case - * that this variable is not set, glib will issue a warning message to - * stderr and return the value of g_get_user_cache_dir(). + * specified in the XDG_RUNTIME_DIR environment variable. + * In the case that this variable is not set, GLib will issue a warning + * message to stderr and return the value of g_get_user_cache_dir(). * * On Windows this is the folder to use for local (as opposed to * roaming) application data. See documentation for @@ -2309,6 +2309,8 @@ g_get_user_cache_dir (void) * what g_get_user_config_dir() returns. * * Returns: a string owned by GLib that must not be modified or freed. + * + * Since: 2.28 **/ const gchar * g_get_user_runtime_dir (void) From db83a96648944bd71ff9c1bd36c7ae898fc06664 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 29 Nov 2010 01:20:58 -0500 Subject: [PATCH 32/44] Documentation tweak --- docs/reference/gobject/gobject-sections.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/reference/gobject/gobject-sections.txt b/docs/reference/gobject/gobject-sections.txt index 9828255a3..7eb75fd01 100644 --- a/docs/reference/gobject/gobject-sections.txt +++ b/docs/reference/gobject/gobject-sections.txt @@ -376,6 +376,7 @@ g_array_get_type g_byte_array_get_type g_ptr_array_get_type g_error_get_type +g_date_time_get_type g_variant_get_gtype g_variant_type_get_gtype
From fcd3e3422749ddbbf29809fcc90ffe8df9d5f696 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 29 Nov 2010 01:39:06 -0500 Subject: [PATCH 33/44] Add new extension point to the list --- docs/reference/gio/overview.xml | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/docs/reference/gio/overview.xml b/docs/reference/gio/overview.xml index 5fdfbf809..3e34ee1e0 100644 --- a/docs/reference/gio/overview.xml +++ b/docs/reference/gio/overview.xml @@ -518,8 +518,10 @@ implementation with the highest priority. - gvfs contains a GConf-based implementation that uses the - same GConf keys as gnome-vfs. + This extension point has been discontinued in GLib 2.28. It is + still available to keep API and ABI stability, but GIO is no + longer using to for default handlers. Instead, the mime handler + mechanism is used, together with x-scheme-handler pseudo-mimetypes. @@ -544,6 +546,24 @@ #GProxy interface, and must be named after the network protocol they are proxying. + + glib-networking contains an implementation of this extension + point based on libproxy. + + + + + G_TLS_BACKEND_EXTENSION_POINT_NAME + + + Allows to provide implementations for TLS support. + Implementations of this extension point must implement + the #GTlsBackend interface. + + + glib-networking contains an implementation of this extension + point. +
From 98bfc8afdaabffe4b63215727a580a139b7f07db Mon Sep 17 00:00:00 2001 From: Aleksander Morgado Date: Thu, 18 Nov 2010 18:00:57 +0100 Subject: [PATCH 34/44] Fixes GB#635187: Always unbox GVariant parameter received via dbus for an action --- gio/gapplicationimpl-dbus.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/gio/gapplicationimpl-dbus.c b/gio/gapplicationimpl-dbus.c index 1aaa3b802..c9f430657 100644 --- a/gio/gapplicationimpl-dbus.c +++ b/gio/gapplicationimpl-dbus.c @@ -354,17 +354,21 @@ g_application_impl_actions_method_call (GDBusConnection *connection, GVariant *platform_data; GVariantIter *param; GVariant *parameter; + GVariant *unboxed_parameter; g_variant_get (parameters, "(&sav@a{sv})", &action_name, ¶m, &platform_data); parameter = g_variant_iter_next_value (param); + unboxed_parameter = parameter ? g_variant_get_variant (parameter) : NULL; g_variant_iter_free (param); class->before_emit (impl->app, platform_data); - g_action_group_activate_action (action_group, action_name, parameter); + g_action_group_activate_action (action_group, action_name, unboxed_parameter); class->after_emit (impl->app, platform_data); g_variant_unref (platform_data); + if (unboxed_parameter) + g_variant_unref (unboxed_parameter); if (parameter) g_variant_unref (parameter); From d7a83d2f590a3568c12a50f31ed5fdc9fc691a47 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 29 Nov 2010 08:10:11 -0500 Subject: [PATCH 35/44] Add another bug --- NEWS | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS b/NEWS index 837160cbb..84cb200dd 100644 --- a/NEWS +++ b/NEWS @@ -29,6 +29,7 @@ Overview of Changes from GLib 2.27.3 to 2.27.4 635640 schema should inherit gettext-domain from schemalist 635768 Protect g_file_monitor_set_rate_limit() against negative... 635882 Fix the wrong-category schema test + 635187 Wrong type of GVariant received in an action... * Updated translations: Galician From 78103b2f1feb5ccbdc97e47d857133826f22820d Mon Sep 17 00:00:00 2001 From: Xan Lopez Date: Mon, 29 Nov 2010 15:29:12 +0100 Subject: [PATCH 36/44] gsettingsschema: plug leak --- gio/gsettingsschema.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gio/gsettingsschema.c b/gio/gsettingsschema.c index 51567c1a3..6d028ad1f 100644 --- a/gio/gsettingsschema.c +++ b/gio/gsettingsschema.c @@ -138,6 +138,8 @@ ensure_schema_lists (void) g_hash_table_insert (single, g_strdup (list[i]), NULL); else g_hash_table_insert (reloc, g_strdup (list[i]), NULL); + + gvdb_table_unref (table); } } From 50a8b039a4323faf0fac68bece1be151f7fd2986 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Mon, 29 Nov 2010 09:36:07 -0500 Subject: [PATCH 37/44] tiny fix to g_io_modules_scan_all_in_directory() docs --- gio/giomodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gio/giomodule.c b/gio/giomodule.c index ecdaab4da..cb05270ca 100644 --- a/gio/giomodule.c +++ b/gio/giomodule.c @@ -278,7 +278,7 @@ is_valid_module_name (const gchar *basename) * g_io_extension_point_get_extension_by_name(). * * If you need to guarantee that all types are loaded in all the modules, - * use g_io_modules_scan_all_in_directory(). + * use g_io_modules_load_all_in_directory(). * * Since: 2.24 **/ From ff8817b631ab11f00c98ed372746b464a440e7c0 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 29 Nov 2010 09:30:07 -0500 Subject: [PATCH 38/44] Update POTFILES.in --- po/POTFILES.in | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/po/POTFILES.in b/po/POTFILES.in index 263184064..a6f3f1578 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -93,7 +93,6 @@ gio/gpermission.c gio/gpollfilemonitor.c gio/gproxyaddress.c gio/gproxyaddressenumerator.c -gio/gproxyconnection.c gio/gresolver.c gio/gseekable.c gio/gsettingsbackend.c @@ -114,6 +113,10 @@ gio/gsocks5proxy.c gio/gtcpconnection.c gio/gthemedicon.c gio/gthreadedsocketservice.c +gio/gtlscertificate.c +gio/gtlsclientconnection.c +gio/gtlsconnection.c +gio/gtlsserverconnection.c gio/gunionvolumemonitor.c gio/gunixconnection.c gio/gunixcredentialsmessage.c From c897dea8c164bc081623c13ac4474bcbd66b908d Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 29 Nov 2010 10:36:43 -0500 Subject: [PATCH 39/44] Bump version --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 930bbdd43..28a1f3967 100644 --- a/configure.ac +++ b/configure.ac @@ -22,7 +22,7 @@ m4_define(glib_configure_ac) # m4_define([glib_major_version], [2]) m4_define([glib_minor_version], [27]) -m4_define([glib_micro_version], [4]) +m4_define([glib_micro_version], [5]) m4_define([glib_interface_age], [0]) m4_define([glib_binary_age], [m4_eval(100 * glib_minor_version + glib_micro_version)]) From fdc6c5fbc171187c6c2d7fdf94d0eea7992d11f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=20Di=C3=A9guez?= Date: Mon, 29 Nov 2010 17:35:51 +0100 Subject: [PATCH 40/44] Updated Galician translations --- po/gl.po | 159 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 86 insertions(+), 73 deletions(-) diff --git a/po/gl.po b/po/gl.po index fd3824e7b..09b0d11a2 100644 --- a/po/gl.po +++ b/po/gl.po @@ -17,8 +17,8 @@ msgid "" msgstr "" "Project-Id-Version: glib.master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-11-13 00:59+0100\n" -"PO-Revision-Date: 2010-11-13 00:59+0100\n" +"POT-Creation-Date: 2010-11-29 17:34+0100\n" +"PO-Revision-Date: 2010-11-29 17:35+0100\n" "Last-Translator: Fran Diéguez \n" "Language-Team: Galician \n" "Language: gl\n" @@ -1427,7 +1427,7 @@ msgstr "O valor de conta pasado a %s é demasiado longo" msgid "Stream is already closed" msgstr "O fluxo xa se pechou" -#: ../gio/gcancellable.c:432 ../gio/gdbusconnection.c:1636 +#: ../gio/gcancellable.c:433 ../gio/gdbusconnection.c:1636 #: ../gio/gdbusconnection.c:1725 ../gio/gdbusconnection.c:1911 #: ../gio/glocalfile.c:2102 ../gio/gsimpleasyncresult.c:811 #: ../gio/gsimpleasyncresult.c:837 @@ -1446,7 +1446,7 @@ msgstr "A secuencia de bytes non é válida na entrada da conversión" msgid "Not enough space in destination" msgstr "Non hai espazo abondo para o enderezo do socket" -#: ../gio/gcharsetconverter.c:447 ../gio/gsocket.c:831 +#: ../gio/gcharsetconverter.c:447 ../gio/gsocket.c:832 msgid "Cancellable initialization not supported" msgstr "Non se permite a inicialización cancelábel" @@ -2012,8 +2012,8 @@ msgid "Type of return value is incorrect, got `%s', expected `%s'" msgstr "" "O tipo do valor de retorno é incorrecto, obtívose «%s» e esperábase «%s»" -#: ../gio/gdbusmethodinvocation.c:406 ../gio/gsocket.c:2992 -#: ../gio/gsocket.c:3073 +#: ../gio/gdbusmethodinvocation.c:406 ../gio/gsocket.c:3023 +#: ../gio/gsocket.c:3104 #, c-format msgid "Error sending message: %s" msgstr "Produciuse un erro ao enviar a mensaxe: %s" @@ -2237,36 +2237,36 @@ msgstr "Camiño do obxecto a monitorizar" msgid "Monitor a remote object." msgstr "Monitoriza un obxecto remoto." -#: ../gio/gdesktopappinfo.c:469 ../gio/gwin32appinfo.c:221 +#: ../gio/gdesktopappinfo.c:471 ../gio/gwin32appinfo.c:221 msgid "Unnamed" msgstr "Sen nome" -#: ../gio/gdesktopappinfo.c:753 +#: ../gio/gdesktopappinfo.c:755 msgid "Desktop file didn't specify Exec field" msgstr "O ficheiro de escritorio non especificou o campo Exec" -#: ../gio/gdesktopappinfo.c:946 +#: ../gio/gdesktopappinfo.c:948 msgid "Unable to find terminal required for application" msgstr "Non é posíbel encontrar o terminal requirido polo aplicativo" -#: ../gio/gdesktopappinfo.c:1155 +#: ../gio/gdesktopappinfo.c:1157 #, c-format msgid "Can't create user application configuration folder %s: %s" msgstr "" "Non é posíbel crear o cartafol de configuración do aplicativo de usuario %s: " "%s" -#: ../gio/gdesktopappinfo.c:1159 +#: ../gio/gdesktopappinfo.c:1161 #, c-format msgid "Can't create user MIME configuration folder %s: %s" msgstr "Non é posíbel crear o cartafol de configuración MIME %s do usuario: %s" -#: ../gio/gdesktopappinfo.c:1567 +#: ../gio/gdesktopappinfo.c:1569 #, c-format msgid "Can't create user desktop file %s" msgstr "Non é posíbel crear o ficheiro de escritorio %s do usuario" -#: ../gio/gdesktopappinfo.c:1681 +#: ../gio/gdesktopappinfo.c:1683 #, c-format msgid "Custom definition for %s" msgstr "Definición personalizada para %s" @@ -2642,58 +2642,58 @@ msgstr "o camiño dunha lista debe rematar con «:/»" msgid "<%s id='%s'> already specified" msgstr "<%s id='%s'> xa especificado" -#: ../gio/glib-compile-schemas.c:1385 +#: ../gio/glib-compile-schemas.c:1387 #, c-format msgid "Element <%s> not allowed inside <%s>" msgstr "Non se permite o elemento <%s> dentro de <%s>" -#: ../gio/glib-compile-schemas.c:1389 +#: ../gio/glib-compile-schemas.c:1391 #, c-format msgid "Element <%s> not allowed at toplevel" msgstr "Non se permite o elemento <%s> non nivel superior" -#: ../gio/glib-compile-schemas.c:1483 +#: ../gio/glib-compile-schemas.c:1485 #, c-format msgid "text may not appear inside <%s>" msgstr "O texto non debe aparecer dentro de <%s>" #. Translators: Do not translate "--strict". -#: ../gio/glib-compile-schemas.c:1652 ../gio/glib-compile-schemas.c:1723 -#: ../gio/glib-compile-schemas.c:1799 +#: ../gio/glib-compile-schemas.c:1654 ../gio/glib-compile-schemas.c:1725 +#: ../gio/glib-compile-schemas.c:1801 #, c-format msgid "--strict was specified; exiting.\n" msgstr "--strict foi especificado; saíndo.\n" -#: ../gio/glib-compile-schemas.c:1660 +#: ../gio/glib-compile-schemas.c:1662 #, c-format msgid "This entire file has been ignored.\n" msgstr "Ignorouse este ficheiro completamente.\n" -#: ../gio/glib-compile-schemas.c:1719 +#: ../gio/glib-compile-schemas.c:1721 #, c-format msgid "Ignoring this file.\n" msgstr "Ignorando este ficheiro.\n" -#: ../gio/glib-compile-schemas.c:1759 +#: ../gio/glib-compile-schemas.c:1761 #, c-format msgid "No such key `%s' in schema `%s' as specified in override file `%s'" msgstr "" "Non existe a chave «%s» no esquema «%s» como se especificou no ficheiro de " "sobrescritura «%s»" -#: ../gio/glib-compile-schemas.c:1765 ../gio/glib-compile-schemas.c:1823 -#: ../gio/glib-compile-schemas.c:1851 +#: ../gio/glib-compile-schemas.c:1767 ../gio/glib-compile-schemas.c:1825 +#: ../gio/glib-compile-schemas.c:1853 #, c-format msgid "; ignoring override for this key.\n" msgstr "; ignorando a sobrescritura para esta chave.\n" -#: ../gio/glib-compile-schemas.c:1769 ../gio/glib-compile-schemas.c:1827 -#: ../gio/glib-compile-schemas.c:1855 +#: ../gio/glib-compile-schemas.c:1771 ../gio/glib-compile-schemas.c:1829 +#: ../gio/glib-compile-schemas.c:1857 #, c-format msgid " and --strict was specified; exiting.\n" msgstr "e --strict foi especificado; saíndo.\n" -#: ../gio/glib-compile-schemas.c:1785 +#: ../gio/glib-compile-schemas.c:1787 #, c-format msgid "" "error parsing key `%s' in schema `%s' as specified in override file `%s': " @@ -2702,12 +2702,12 @@ msgstr "" "produciuse un erro ao analizar a chave «%s» no esquema «%s» como se " "especificou no ficheiro de sobrescritura «%s»: %s. " -#: ../gio/glib-compile-schemas.c:1795 +#: ../gio/glib-compile-schemas.c:1797 #, c-format msgid "Ignoring override for this key.\n" msgstr "Ignorando a sobrescritura para esta chave.\n" -#: ../gio/glib-compile-schemas.c:1813 +#: ../gio/glib-compile-schemas.c:1815 #, c-format msgid "" "override for key `%s' in schema `%s' in override file `%s' is out of the " @@ -2716,7 +2716,7 @@ msgstr "" "a chave de sobrescritura «%s» no esquema «%s» no ficheiro de sobrescritura " "«%s» está fora do rango fornecido no esquema" -#: ../gio/glib-compile-schemas.c:1841 +#: ../gio/glib-compile-schemas.c:1843 #, c-format msgid "" "override for key `%s' in schema `%s' in override file `%s' is not in the " @@ -2725,31 +2725,31 @@ msgstr "" "a chave de sobrescritura «%s» no esquema «%s» no ficheiro de sobrescritura " "«%s» non está na lista de opcións válidas" -#: ../gio/glib-compile-schemas.c:1895 +#: ../gio/glib-compile-schemas.c:1897 msgid "where to store the gschemas.compiled file" msgstr "onde almacenar o ficheiro compilado de gschemas" -#: ../gio/glib-compile-schemas.c:1895 ../gio/glib-compile-schemas.c:1908 +#: ../gio/glib-compile-schemas.c:1897 ../gio/glib-compile-schemas.c:1910 msgid "DIRECTORY" msgstr "DIRECTORIO" -#: ../gio/glib-compile-schemas.c:1896 +#: ../gio/glib-compile-schemas.c:1898 msgid "Abort on any errors in schemas" msgstr "Abortar ao encontrar calquera erro nos esquemas" -#: ../gio/glib-compile-schemas.c:1897 +#: ../gio/glib-compile-schemas.c:1899 msgid "Do not write the gschema.compiled file" msgstr "Non escribir o ficheiro compilado de gschema" -#: ../gio/glib-compile-schemas.c:1898 +#: ../gio/glib-compile-schemas.c:1900 msgid "This option will be removed soon." msgstr "Esta opción eliminarase pronto" -#: ../gio/glib-compile-schemas.c:1899 +#: ../gio/glib-compile-schemas.c:1901 msgid "Do not enforce key name restrictions" msgstr "Non respetar as restricións de nome de chave" -#: ../gio/glib-compile-schemas.c:1911 +#: ../gio/glib-compile-schemas.c:1913 msgid "" "Compile all GSettings schema files into a schema cache.\n" "Schema files are required to have the extension .gschema.xml,\n" @@ -2759,22 +2759,22 @@ msgstr "" "de esquemas. Os ficheiros de esquema deben ter a extensión\n" ".gschema.xml e o ficheiro de caché chámase gschemas.compiled." -#: ../gio/glib-compile-schemas.c:1927 +#: ../gio/glib-compile-schemas.c:1929 #, c-format msgid "You should give exactly one directory name\n" msgstr "Debería fornecer exactamente un nome de cartafol\n" -#: ../gio/glib-compile-schemas.c:1966 +#: ../gio/glib-compile-schemas.c:1968 #, c-format msgid "No schema files found: " msgstr "Non se encontraron ficheiros de esquema: " -#: ../gio/glib-compile-schemas.c:1969 +#: ../gio/glib-compile-schemas.c:1971 #, c-format msgid "doing nothing.\n" msgstr "sen facer nada.\n" -#: ../gio/glib-compile-schemas.c:1972 +#: ../gio/glib-compile-schemas.c:1974 #, c-format msgid "removed existing output file.\n" msgstr "eliminouse o ficheiro de saída existente.\n" @@ -3401,124 +3401,124 @@ msgstr " VALUE O valor a estabelecer\n" msgid "Empty schema name given" msgstr "Forneceuse un nome de esquema baleiros" -#: ../gio/gsocket.c:276 +#: ../gio/gsocket.c:277 msgid "Invalid socket, not initialized" msgstr "O socket non é correcto, non se inicialiou" -#: ../gio/gsocket.c:283 +#: ../gio/gsocket.c:284 #, c-format msgid "Invalid socket, initialization failed due to: %s" msgstr "O socket non é correcto, a inicialización fallou debido a: %s" -#: ../gio/gsocket.c:291 +#: ../gio/gsocket.c:292 msgid "Socket is already closed" msgstr "O fluxo de orixe xa está pechado" -#: ../gio/gsocket.c:299 ../gio/gsocket.c:2734 ../gio/gsocket.c:2778 +#: ../gio/gsocket.c:300 ../gio/gsocket.c:2765 ../gio/gsocket.c:2809 msgid "Socket I/O timed out" msgstr "Tempo de espera do Socket de E/S superado" -#: ../gio/gsocket.c:442 +#: ../gio/gsocket.c:443 #, c-format msgid "creating GSocket from fd: %s" msgstr "creando o GSocket a partir de fd: %s" -#: ../gio/gsocket.c:476 ../gio/gsocket.c:492 ../gio/gsocket.c:2134 +#: ../gio/gsocket.c:477 ../gio/gsocket.c:493 ../gio/gsocket.c:2135 #, c-format msgid "Unable to create socket: %s" msgstr "Non é posíbel crear o socket: %s" -#: ../gio/gsocket.c:476 +#: ../gio/gsocket.c:477 msgid "Unknown protocol was specified" msgstr "Foi especificado un protocolo descoñecido" -#: ../gio/gsocket.c:1245 +#: ../gio/gsocket.c:1246 #, c-format msgid "could not get local address: %s" msgstr "Non foi posíbel obter un enderezo local: %s" -#: ../gio/gsocket.c:1288 +#: ../gio/gsocket.c:1289 #, c-format msgid "could not get remote address: %s" msgstr "non foi posíbel obter un enderezo remoto: %s" -#: ../gio/gsocket.c:1349 +#: ../gio/gsocket.c:1350 #, c-format msgid "could not listen: %s" msgstr "non foi posíbel escoitar: %s" -#: ../gio/gsocket.c:1423 +#: ../gio/gsocket.c:1424 #, c-format msgid "Error binding to address: %s" msgstr "Produciuse un erro ao conectar co enderezo: %s" -#: ../gio/gsocket.c:1543 +#: ../gio/gsocket.c:1544 #, c-format msgid "Error accepting connection: %s" msgstr "Produciuse un erro ao aceptar a conexión : %s" -#: ../gio/gsocket.c:1660 +#: ../gio/gsocket.c:1661 msgid "Error connecting: " msgstr "Produciuse un erro ao conectar: " -#: ../gio/gsocket.c:1665 +#: ../gio/gsocket.c:1666 msgid "Connection in progress" msgstr "Conexión en marcha" -#: ../gio/gsocket.c:1672 +#: ../gio/gsocket.c:1673 #, c-format msgid "Error connecting: %s" msgstr "Produciuse un erro ao conectar: %s" -#: ../gio/gsocket.c:1715 ../gio/gsocket.c:3497 +#: ../gio/gsocket.c:1716 ../gio/gsocket.c:3528 #, c-format msgid "Unable to get pending error: %s" msgstr "Non é posíbel obter o erro pendente: %s" -#: ../gio/gsocket.c:1847 +#: ../gio/gsocket.c:1848 #, c-format msgid "Error receiving data: %s" msgstr "Produciuse un erro ao recibir datos: %s" -#: ../gio/gsocket.c:2021 +#: ../gio/gsocket.c:2022 #, c-format msgid "Error sending data: %s" msgstr "Produciuse un erro ao enviar datos: %s" -#: ../gio/gsocket.c:2213 +#: ../gio/gsocket.c:2214 #, c-format msgid "Error closing socket: %s" msgstr "Produciuse un erro ao pechar o socket: %s" -#: ../gio/gsocket.c:2727 +#: ../gio/gsocket.c:2758 #, c-format msgid "Waiting for socket condition: %s" msgstr "Agardando pola situación do socket: %s" -#: ../gio/gsocket.c:3017 +#: ../gio/gsocket.c:3048 msgid "GSocketControlMessage not supported on windows" msgstr "O GSocketControlMessage non está permitido en windows" -#: ../gio/gsocket.c:3276 ../gio/gsocket.c:3417 +#: ../gio/gsocket.c:3307 ../gio/gsocket.c:3448 #, c-format msgid "Error receiving message: %s" msgstr "Produciuse un erro ao recibir a mensaxe: %s" -#: ../gio/gsocket.c:3512 +#: ../gio/gsocket.c:3543 msgid "g_socket_get_credentials not implemented for this OS" msgstr "" "g_socket_get_credentials non está implementado para este sistema operativo" -#: ../gio/gsocketclient.c:674 ../gio/gsocketclient.c:1152 +#: ../gio/gsocketclient.c:798 ../gio/gsocketclient.c:1364 msgid "Unknown error on connect" msgstr "Erro descoñecido ao conectar" -#: ../gio/gsocketclient.c:711 ../gio/gsocketclient.c:1037 +#: ../gio/gsocketclient.c:836 ../gio/gsocketclient.c:1248 msgid "Trying to proxy over non-TCP connection is not supported." msgstr "" "Non se permite a conexión ao proxy mediante unha conexión que non sexa TCP." -#: ../gio/gsocketclient.c:749 ../gio/gsocketclient.c:1060 +#: ../gio/gsocketclient.c:858 ../gio/gsocketclient.c:1273 #, c-format msgid "Proxy protocol '%s' is not supported." msgstr "Non é posíbel usar o proxy co protocolo «%s»" @@ -3566,7 +3566,8 @@ msgstr "O proxy SOCKSv5 require autenticación." #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by " +"GLib." msgstr "" "SOCKSv5 require un método de autenticación que non é compatíbel con GLib." @@ -3631,6 +3632,18 @@ msgstr "Produciuse un erro no proxy SOCKSv5 descoñecido." msgid "Can't handle version %d of GThemedIcon encoding" msgstr "Non é posíbel manipular a versión %d da codificación de GThemedIcon" +#: ../gio/gtlscertificate.c:270 +msgid "No PEM-encoded certificate found" +msgstr "Non se encontrou ningún certificado PEM codificado" + +#: ../gio/gtlscertificate.c:279 +msgid "Could not parse PEM-encoded certificate" +msgstr "Non foi posíbel analizar o certificado PEM codificado" + +#: ../gio/gtlscertificate.c:300 +msgid "Could not parse PEM-encoded private key" +msgstr "Non foi posíbel analizar a chave privada PEM codificada" + #: ../gio/gunixconnection.c:164 ../gio/gunixconnection.c:505 #, c-format msgid "Expecting 1 control message, got %d" @@ -3685,14 +3698,14 @@ msgstr "" msgid "Error while disabling SO_PASSCRED: %s" msgstr "Produciuse un erro ao desactivar SO_PASSCRED: %s" -#: ../gio/gunixinputstream.c:353 ../gio/gunixinputstream.c:373 -#: ../gio/gunixinputstream.c:451 +#: ../gio/gunixinputstream.c:368 ../gio/gunixinputstream.c:388 +#: ../gio/gunixinputstream.c:466 #, c-format msgid "Error reading from unix: %s" msgstr "Produciuse un erro ao ler de unix: %s" -#: ../gio/gunixinputstream.c:406 ../gio/gunixinputstream.c:586 -#: ../gio/gunixoutputstream.c:393 ../gio/gunixoutputstream.c:542 +#: ../gio/gunixinputstream.c:421 ../gio/gunixinputstream.c:601 +#: ../gio/gunixoutputstream.c:407 ../gio/gunixoutputstream.c:556 #, c-format msgid "Error closing unix: %s" msgstr "Produciuse un erro ao pechar unix: %s" @@ -3701,8 +3714,8 @@ msgstr "Produciuse un erro ao pechar unix: %s" msgid "Filesystem root" msgstr "Raíz do sistema de ficheiros" -#: ../gio/gunixoutputstream.c:339 ../gio/gunixoutputstream.c:360 -#: ../gio/gunixoutputstream.c:438 +#: ../gio/gunixoutputstream.c:353 ../gio/gunixoutputstream.c:374 +#: ../gio/gunixoutputstream.c:452 #, c-format msgid "Error writing to unix: %s" msgstr "Produciuse un erro ao escribir a unix: %s" From c541d234855dc7466c57ebfc3dc44b1829d9a900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Gonz=C3=A1lez?= Date: Tue, 30 Nov 2010 23:42:08 +0100 Subject: [PATCH 41/44] Updated Spanish translation --- po/es.po | 329 +++++++++++++++++++++++++++---------------------------- 1 file changed, 163 insertions(+), 166 deletions(-) diff --git a/po/es.po b/po/es.po index 186ce060e..922fc4426 100644 --- a/po/es.po +++ b/po/es.po @@ -12,8 +12,8 @@ msgstr "" "Project-Id-Version: glib.master\n" "Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?" "product=glib&component=general\n" -"POT-Creation-Date: 2010-10-31 16:30+0000\n" -"PO-Revision-Date: 2010-11-02 10:44+0100\n" +"POT-Creation-Date: 2010-11-29 15:49+0000\n" +"PO-Revision-Date: 2010-11-30 23:40+0100\n" "Last-Translator: Jorge González \n" "Language-Team: Español \n" "MIME-Version: 1.0\n" @@ -1404,21 +1404,21 @@ msgstr "El valor «%s» no puede interpretarse como un booleano." #: ../gio/gbufferedinputstream.c:411 ../gio/gbufferedinputstream.c:492 #: ../gio/ginputstream.c:185 ../gio/ginputstream.c:317 -#: ../gio/ginputstream.c:556 ../gio/ginputstream.c:681 -#: ../gio/goutputstream.c:198 ../gio/goutputstream.c:725 +#: ../gio/ginputstream.c:556 ../gio/ginputstream.c:680 +#: ../gio/goutputstream.c:198 ../gio/goutputstream.c:726 #, c-format msgid "Too large count value passed to %s" msgstr "El valor de conteo pasado a %s es demasiado largo" -#: ../gio/gbufferedinputstream.c:881 ../gio/ginputstream.c:891 -#: ../gio/giostream.c:306 ../gio/goutputstream.c:1200 +#: ../gio/gbufferedinputstream.c:880 ../gio/ginputstream.c:888 +#: ../gio/giostream.c:306 ../gio/goutputstream.c:1197 msgid "Stream is already closed" msgstr "El flujo ya se cerró" -#: ../gio/gcancellable.c:432 ../gio/gdbusconnection.c:1642 -#: ../gio/gdbusconnection.c:1731 ../gio/gdbusconnection.c:1917 -#: ../gio/glocalfile.c:2102 ../gio/gsimpleasyncresult.c:755 -#: ../gio/gsimpleasyncresult.c:781 +#: ../gio/gcancellable.c:433 ../gio/gdbusconnection.c:1636 +#: ../gio/gdbusconnection.c:1725 ../gio/gdbusconnection.c:1911 +#: ../gio/glocalfile.c:2102 ../gio/gsimpleasyncresult.c:811 +#: ../gio/gsimpleasyncresult.c:837 msgid "Operation was cancelled" msgstr "Se canceló la operación" @@ -1434,7 +1434,7 @@ msgstr "Secuencia multibyte incompleta en la entrada" msgid "Not enough space in destination" msgstr "No hay suficiente espacio en el destino" -#: ../gio/gcharsetconverter.c:447 ../gio/gsocket.c:831 +#: ../gio/gcharsetconverter.c:447 ../gio/gsocket.c:832 msgid "Cancellable initialization not supported" msgstr "La inicialización cancelable no eestá soportada" @@ -1580,40 +1580,40 @@ msgstr "" "Error al escribir el contenido del archivo de número usado una sola vez «%s» " "al flujo:" -#: ../gio/gdbusaddress.c:942 +#: ../gio/gdbusaddress.c:939 msgid "The given address is empty" msgstr "La dirección proporcionada está vacía" -#: ../gio/gdbusaddress.c:1011 +#: ../gio/gdbusaddress.c:1008 msgid "Cannot spawn a message bus without a machine-id: " msgstr "No se puede lanzar («spawn») un mensaje al bus sin un ID de máquina: " -#: ../gio/gdbusaddress.c:1048 +#: ../gio/gdbusaddress.c:1045 #, c-format msgid "Error spawning command line `%s': " msgstr "Error al lanzar («spawn») el comando «%s»: " -#: ../gio/gdbusaddress.c:1059 +#: ../gio/gdbusaddress.c:1056 #, c-format msgid "Abnormal program termination spawning command line `%s': %s" msgstr "" "Terminación anómala de programa al lanzar («spawn») el comando «%s»: %s" -#: ../gio/gdbusaddress.c:1073 +#: ../gio/gdbusaddress.c:1070 #, c-format msgid "Command line `%s' exited with non-zero exit status %d: %s" msgstr "" "El comando de línea «%s» finalizó con un estado de salida distinto de cero " "%d: %s" -#: ../gio/gdbusaddress.c:1146 +#: ../gio/gdbusaddress.c:1143 #, c-format msgid "Cannot determine session bus address (not implemented for this OS)" msgstr "" "No se puede determinar la dirección del bus de sesión (no implementado para " "este SO)" -#: ../gio/gdbusaddress.c:1245 ../gio/gdbusconnection.c:6158 +#: ../gio/gdbusaddress.c:1242 ../gio/gdbusconnection.c:6167 #, c-format msgid "" "Cannot determine bus address from DBUS_STARTER_BUS_TYPE environment variable " @@ -1622,7 +1622,7 @@ msgstr "" "No se puede determinar la dirección del bus desde la variable de entorno " "DBUS_STARTER_BUS_TYPE; variable «%s» desconocida" -#: ../gio/gdbusaddress.c:1254 ../gio/gdbusconnection.c:6167 +#: ../gio/gdbusaddress.c:1251 ../gio/gdbusconnection.c:6176 msgid "" "Cannot determine bus address because the DBUS_STARTER_BUS_TYPE environment " "variable is not set" @@ -1630,7 +1630,7 @@ msgstr "" "No se puede determinar la dirección del bus porque la variable de entorno " "DBUS_STARTER_BUS_TYPE no está establecida" -#: ../gio/gdbusaddress.c:1264 +#: ../gio/gdbusaddress.c:1261 #, c-format msgid "Unknown bus type %d" msgstr "Tipo de bus %d desconocido" @@ -1738,23 +1738,23 @@ msgid "(Additionally, releasing the lock for `%s' also failed: %s) " msgstr "" "(Adicionalmente, también falló la liberación del bloqueo para «%s»: %s)" -#: ../gio/gdbusconnection.c:1151 ../gio/gdbusconnection.c:1380 -#: ../gio/gdbusconnection.c:1419 ../gio/gdbusconnection.c:1742 +#: ../gio/gdbusconnection.c:1148 ../gio/gdbusconnection.c:1374 +#: ../gio/gdbusconnection.c:1413 ../gio/gdbusconnection.c:1736 msgid "The connection is closed" msgstr "La conexión está cerrada" -#: ../gio/gdbusconnection.c:1686 +#: ../gio/gdbusconnection.c:1680 msgid "Timeout was reached" msgstr "Se alcanzó el tiempo de expiración" -#: ../gio/gdbusconnection.c:2305 +#: ../gio/gdbusconnection.c:2299 msgid "" "Unsupported flags encountered when constructing a client-side connection" msgstr "" "Se encontraron opciones no soportadas al construir la conexión del lado del " "cliente" -#: ../gio/gdbusconnection.c:3739 ../gio/gdbusconnection.c:4057 +#: ../gio/gdbusconnection.c:3751 ../gio/gdbusconnection.c:4069 #, c-format msgid "" "No such interface `org.freedesktop.DBus.Properties' on object at path %s" @@ -1762,68 +1762,68 @@ msgstr "" "No existe la interfaz «org.freedesktop.DBus.Properties» en el objeto en la " "ruta %s" -#: ../gio/gdbusconnection.c:3811 +#: ../gio/gdbusconnection.c:3823 #, c-format msgid "Error setting property `%s': Expected type `%s' but got `%s'" msgstr "" "Error al establecer la propiedad «%s». Se esperaba el tipo «%s» pero se " "obtuvo «%s»." -#: ../gio/gdbusconnection.c:3906 +#: ../gio/gdbusconnection.c:3918 #, c-format msgid "No such property `%s'" msgstr "No existe la propiedad «%s»" -#: ../gio/gdbusconnection.c:3918 +#: ../gio/gdbusconnection.c:3930 #, c-format msgid "Property `%s' is not readable" msgstr "No se puede leer la clave «%s»" -#: ../gio/gdbusconnection.c:3929 +#: ../gio/gdbusconnection.c:3941 #, c-format msgid "Property `%s' is not writable" msgstr "No se puede escribir la clave «%s»" -#: ../gio/gdbusconnection.c:3999 ../gio/gdbusconnection.c:5592 +#: ../gio/gdbusconnection.c:4011 ../gio/gdbusconnection.c:5601 #, c-format msgid "No such interface `%s'" msgstr "La interfaz «%s» no existe" -#: ../gio/gdbusconnection.c:4187 +#: ../gio/gdbusconnection.c:4199 msgid "No such interface" msgstr "No existe tal interfaz" -#: ../gio/gdbusconnection.c:4403 ../gio/gdbusconnection.c:6108 +#: ../gio/gdbusconnection.c:4415 ../gio/gdbusconnection.c:6117 #, c-format msgid "No such interface `%s' on object at path %s" msgstr "No existe la interfaz «%s» en el objeto en la ruta %s" -#: ../gio/gdbusconnection.c:4455 +#: ../gio/gdbusconnection.c:4467 #, c-format msgid "No such method `%s'" msgstr "No existe el método «%s»" -#: ../gio/gdbusconnection.c:4486 +#: ../gio/gdbusconnection.c:4498 #, c-format msgid "Type of message, `%s', does not match expected type `%s'" msgstr "El tipo de mensaje, «%s», no concide con el tipo esperado «%s»" -#: ../gio/gdbusconnection.c:4705 +#: ../gio/gdbusconnection.c:4717 #, c-format msgid "An object is already exported for the interface %s at %s" msgstr "Ya existe un objeto exportado para la interfaz %s en %s" -#: ../gio/gdbusconnection.c:4899 +#: ../gio/gdbusconnection.c:4911 #, c-format msgid "Method `%s' returned type `%s', but expected `%s'" msgstr "El método «%s» devolvió el tipo «%s» pero se esperaba «%s»" -#: ../gio/gdbusconnection.c:5703 +#: ../gio/gdbusconnection.c:5712 #, c-format msgid "Method `%s' on interface `%s' with signature `%s' does not exist" msgstr "El método «%s» con interfaz «%s» y firma «%s» no existe" -#: ../gio/gdbusconnection.c:5821 +#: ../gio/gdbusconnection.c:5830 #, c-format msgid "A subtree is already exported for %s" msgstr "Ya se ha exportado un subárbol para %s" @@ -2013,13 +2013,13 @@ msgid "Type of return value is incorrect, got `%s', expected `%s'" msgstr "" "El tipo del valor devuelto es incorrecto, se obtuvo «%s», se esperaba «%s»" -#: ../gio/gdbusmethodinvocation.c:406 ../gio/gsocket.c:2995 -#: ../gio/gsocket.c:3076 +#: ../gio/gdbusmethodinvocation.c:406 ../gio/gsocket.c:3023 +#: ../gio/gsocket.c:3104 #, c-format msgid "Error sending message: %s" msgstr "Error al enviar el mensaje: %s" -#: ../gio/gdbusprivate.c:1759 +#: ../gio/gdbusprivate.c:1756 msgid "Unable to load /var/lib/dbus/machine-id: " msgstr "No se puede cargar /var/lib/dbus/machine-id: " @@ -2032,17 +2032,17 @@ msgstr "" "Intentando establecer la propiedad %s del tipo %s pero según la interfaz " "esperada el tipo es %s" -#: ../gio/gdbusproxy.c:1235 +#: ../gio/gdbusproxy.c:1234 #, c-format msgid "Error calling StartServiceByName for %s: " msgstr "Error al llamar StartSereviceByName para %s: " -#: ../gio/gdbusproxy.c:1256 +#: ../gio/gdbusproxy.c:1255 #, c-format msgid "Unexpected reply %d from StartServiceByName(\"%s\") method" msgstr "Respuesta %d no esperada del método StartServiceByName(«%s»)" -#: ../gio/gdbusproxy.c:2316 ../gio/gdbusproxy.c:2474 +#: ../gio/gdbusproxy.c:2311 ../gio/gdbusproxy.c:2469 msgid "" "Cannot invoke method; proxy is for a well-known name without an owner and " "proxy was constructed with the G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START flag" @@ -2241,36 +2241,36 @@ msgstr "Ruta objeto para monitorizar" msgid "Monitor a remote object." msgstr "Monitorizar un objeto remoto." -#: ../gio/gdesktopappinfo.c:467 ../gio/gwin32appinfo.c:221 +#: ../gio/gdesktopappinfo.c:471 ../gio/gwin32appinfo.c:221 msgid "Unnamed" msgstr "Sin nombre" -#: ../gio/gdesktopappinfo.c:751 +#: ../gio/gdesktopappinfo.c:755 msgid "Desktop file didn't specify Exec field" msgstr "El archivo de escritorio no especificó el campo Exec" -#: ../gio/gdesktopappinfo.c:944 +#: ../gio/gdesktopappinfo.c:948 msgid "Unable to find terminal required for application" msgstr "Imposible encontrar el terminal requerido por la aplicación" -#: ../gio/gdesktopappinfo.c:1153 +#: ../gio/gdesktopappinfo.c:1157 #, c-format msgid "Can't create user application configuration folder %s: %s" msgstr "" "No se puede crear la carpeta de configuración de la aplicación %s del " "usuario: %s" -#: ../gio/gdesktopappinfo.c:1157 +#: ../gio/gdesktopappinfo.c:1161 #, c-format msgid "Can't create user MIME configuration folder %s: %s" msgstr "No se puede crear la carpeta de configuración MIME %s del usuario: %s" -#: ../gio/gdesktopappinfo.c:1565 +#: ../gio/gdesktopappinfo.c:1569 #, c-format msgid "Can't create user desktop file %s" msgstr "No se puede crear el archivo de escritorio %s del usuario" -#: ../gio/gdesktopappinfo.c:1679 +#: ../gio/gdesktopappinfo.c:1683 #, c-format msgid "Custom definition for %s" msgstr "Definición personalizada para %s" @@ -2329,8 +2329,8 @@ msgstr "Se esperaba un GEmblem para GEmblemedIconjo" #: ../gio/gfile.c:3493 ../gio/gfile.c:3534 ../gio/gfile.c:3861 #: ../gio/gfile.c:4263 ../gio/gfile.c:4349 ../gio/gfile.c:4438 #: ../gio/gfile.c:4536 ../gio/gfile.c:4623 ../gio/gfile.c:4717 -#: ../gio/gfile.c:5047 ../gio/gfile.c:5327 ../gio/gfile.c:5396 -#: ../gio/gfile.c:6988 ../gio/gfile.c:7078 ../gio/gfile.c:7164 +#: ../gio/gfile.c:5038 ../gio/gfile.c:5305 ../gio/gfile.c:5370 +#: ../gio/gfile.c:6944 ../gio/gfile.c:7034 ../gio/gfile.c:7120 #: ../gio/win32/gwinhttpfile.c:439 msgid "Operation not supported" msgstr "Operación no soportada" @@ -2390,11 +2390,11 @@ msgstr "No se soporta mover a la papelera" msgid "File names cannot contain '%c'" msgstr "Los nombres de archivo no pueden contener «%c»" -#: ../gio/gfile.c:6045 ../gio/gvolume.c:332 +#: ../gio/gfile.c:6003 ../gio/gvolume.c:332 msgid "volume doesn't implement mount" msgstr "el volumen no implementa el montado" -#: ../gio/gfile.c:6156 +#: ../gio/gfile.c:6114 msgid "No application is registered as handling this file" msgstr "No hay ninguna aplicación registrada para manejar este archivo" @@ -2420,22 +2420,22 @@ msgstr "No se puede manejar la versión %d de la codificación GFileIcon" msgid "Malformed input data for GFileIcon" msgstr "Datos de entrada mal formados para GFileIcon" -#: ../gio/gfileinputstream.c:154 ../gio/gfileinputstream.c:421 +#: ../gio/gfileinputstream.c:154 ../gio/gfileinputstream.c:420 #: ../gio/gfileiostream.c:170 ../gio/gfileoutputstream.c:169 -#: ../gio/gfileoutputstream.c:524 +#: ../gio/gfileoutputstream.c:523 msgid "Stream doesn't support query_info" msgstr "El flujo no soporta query_info" -#: ../gio/gfileinputstream.c:336 ../gio/gfileiostream.c:388 -#: ../gio/gfileoutputstream.c:382 +#: ../gio/gfileinputstream.c:335 ../gio/gfileiostream.c:387 +#: ../gio/gfileoutputstream.c:381 msgid "Seek not supported on stream" msgstr "No se permite buscar en el flujo" -#: ../gio/gfileinputstream.c:380 +#: ../gio/gfileinputstream.c:379 msgid "Truncate not allowed on input stream" msgstr "No se permite truncar en el flujo de entrada" -#: ../gio/gfileiostream.c:464 ../gio/gfileoutputstream.c:458 +#: ../gio/gfileiostream.c:463 ../gio/gfileoutputstream.c:457 msgid "Truncate not supported on stream" msgstr "No se soporta el truncamiento en el flujo" @@ -2484,8 +2484,8 @@ msgstr "El flujo de entrada no implementa la lectura" #. Translators: This is an error you get if there is #. * already an operation running against this stream when #. * you try to start one -#: ../gio/ginputstream.c:901 ../gio/giostream.c:316 -#: ../gio/goutputstream.c:1210 +#: ../gio/ginputstream.c:898 ../gio/giostream.c:316 +#: ../gio/goutputstream.c:1207 msgid "Stream has outstanding operation" msgstr "El flujo tiene una operación excepcional" @@ -2645,58 +2645,58 @@ msgstr "la ruta de la lista debe terminar con «:/»" msgid "<%s id='%s'> already specified" msgstr "<%s id='%s'> ya especificado" -#: ../gio/glib-compile-schemas.c:1385 +#: ../gio/glib-compile-schemas.c:1387 #, c-format msgid "Element <%s> not allowed inside <%s>" msgstr "No se permite el elemento <%s> dentro de <%s>" -#: ../gio/glib-compile-schemas.c:1389 +#: ../gio/glib-compile-schemas.c:1391 #, c-format msgid "Element <%s> not allowed at toplevel" msgstr "No se permite el elemento <%s> en el nivel superior" -#: ../gio/glib-compile-schemas.c:1483 +#: ../gio/glib-compile-schemas.c:1485 #, c-format msgid "text may not appear inside <%s>" msgstr "El texto no debe aparecer dentro de <%s>" #. Translators: Do not translate "--strict". -#: ../gio/glib-compile-schemas.c:1652 ../gio/glib-compile-schemas.c:1723 -#: ../gio/glib-compile-schemas.c:1799 +#: ../gio/glib-compile-schemas.c:1654 ../gio/glib-compile-schemas.c:1725 +#: ../gio/glib-compile-schemas.c:1801 #, c-format msgid "--strict was specified; exiting.\n" msgstr "se especificó --strict; saliendo.\n" -#: ../gio/glib-compile-schemas.c:1660 +#: ../gio/glib-compile-schemas.c:1662 #, c-format msgid "This entire file has been ignored.\n" msgstr "Se ha ignorado este archivo completamente.\n" -#: ../gio/glib-compile-schemas.c:1719 +#: ../gio/glib-compile-schemas.c:1721 #, c-format msgid "Ignoring this file.\n" msgstr "Ignorando este archivo.\n" -#: ../gio/glib-compile-schemas.c:1759 +#: ../gio/glib-compile-schemas.c:1761 #, c-format msgid "No such key `%s' in schema `%s' as specified in override file `%s'" msgstr "" "No existe la clave «%s» en el esquema «%s» como se especificó en el archivo " "de sobreescitura «%s»" -#: ../gio/glib-compile-schemas.c:1765 ../gio/glib-compile-schemas.c:1823 -#: ../gio/glib-compile-schemas.c:1851 +#: ../gio/glib-compile-schemas.c:1767 ../gio/glib-compile-schemas.c:1825 +#: ../gio/glib-compile-schemas.c:1853 #, c-format msgid "; ignoring override for this key.\n" msgstr "; ignorando la sobreescritura para esta clave.\n" -#: ../gio/glib-compile-schemas.c:1769 ../gio/glib-compile-schemas.c:1827 -#: ../gio/glib-compile-schemas.c:1855 +#: ../gio/glib-compile-schemas.c:1771 ../gio/glib-compile-schemas.c:1829 +#: ../gio/glib-compile-schemas.c:1857 #, c-format msgid " and --strict was specified; exiting.\n" msgstr "y se especificó --strict; saliendo.\n" -#: ../gio/glib-compile-schemas.c:1785 +#: ../gio/glib-compile-schemas.c:1787 #, c-format msgid "" "error parsing key `%s' in schema `%s' as specified in override file `%s': " @@ -2705,12 +2705,12 @@ msgstr "" "error al analizar la clave «%s» en el esquema «%s» como se especificó en el " "archivo de sobreescritura «%s»: %s." -#: ../gio/glib-compile-schemas.c:1795 +#: ../gio/glib-compile-schemas.c:1797 #, c-format msgid "Ignoring override for this key.\n" msgstr "Ignorando la sobreescritura para esta clave.\n" -#: ../gio/glib-compile-schemas.c:1813 +#: ../gio/glib-compile-schemas.c:1815 #, c-format msgid "" "override for key `%s' in schema `%s' in override file `%s' is out of the " @@ -2719,7 +2719,7 @@ msgstr "" "la clave de sobreescritura «%s» en el esquema «%s» en el archivo de " "sobreescritura «%s» está fuera del rango proporcionado en el esquema" -#: ../gio/glib-compile-schemas.c:1841 +#: ../gio/glib-compile-schemas.c:1843 #, c-format msgid "" "override for key `%s' in schema `%s' in override file `%s' is not in the " @@ -2728,31 +2728,31 @@ msgstr "" "la clave de sobreescritura «%s» en el esquema «%s» en el archivo de " "sobreescritura «%s» no está en la lista de opciones válidas" -#: ../gio/glib-compile-schemas.c:1895 +#: ../gio/glib-compile-schemas.c:1897 msgid "where to store the gschemas.compiled file" msgstr "dónde almacenar el archivo gschemas.compiled" -#: ../gio/glib-compile-schemas.c:1895 ../gio/glib-compile-schemas.c:1908 +#: ../gio/glib-compile-schemas.c:1897 ../gio/glib-compile-schemas.c:1910 msgid "DIRECTORY" msgstr "DIRECTORIO" -#: ../gio/glib-compile-schemas.c:1896 +#: ../gio/glib-compile-schemas.c:1898 msgid "Abort on any errors in schemas" msgstr "Abortar ante cualquier error en los esquemas" -#: ../gio/glib-compile-schemas.c:1897 +#: ../gio/glib-compile-schemas.c:1899 msgid "Do not write the gschema.compiled file" msgstr "No escribir el archivo gschemas.compiled" -#: ../gio/glib-compile-schemas.c:1898 +#: ../gio/glib-compile-schemas.c:1900 msgid "This option will be removed soon." msgstr "Pronto se quitará esta opción." -#: ../gio/glib-compile-schemas.c:1899 +#: ../gio/glib-compile-schemas.c:1901 msgid "Do not enforce key name restrictions" msgstr "No forzar las restricciones de nombre de las claves" -#: ../gio/glib-compile-schemas.c:1911 +#: ../gio/glib-compile-schemas.c:1913 msgid "" "Compile all GSettings schema files into a schema cache.\n" "Schema files are required to have the extension .gschema.xml,\n" @@ -2763,22 +2763,22 @@ msgstr "" "Los archivos de esquema deben tener la extensión .gschema.xml,\n" "y el archivo de caché se llama gschemas.compiled." -#: ../gio/glib-compile-schemas.c:1927 +#: ../gio/glib-compile-schemas.c:1929 #, c-format msgid "You should give exactly one directory name\n" msgstr "Deberá proporcionar exactamente un nombre de directorio\n" -#: ../gio/glib-compile-schemas.c:1966 +#: ../gio/glib-compile-schemas.c:1968 #, c-format msgid "No schema files found: " msgstr "No se encontró ningún archivo de esquemas: " -#: ../gio/glib-compile-schemas.c:1969 +#: ../gio/glib-compile-schemas.c:1971 #, c-format msgid "doing nothing.\n" msgstr "sin hacer nada.\n" -#: ../gio/glib-compile-schemas.c:1972 +#: ../gio/glib-compile-schemas.c:1974 #, c-format msgid "removed existing output file.\n" msgstr "se quitó el archivo de salida existente.\n" @@ -3207,7 +3207,6 @@ msgstr "El esquema «%s» no es reubicable (no se debe especificar la ruta)\n" #: ../gio/gsettings-tool.c:65 ../gio/gsettings-tool.c:82 #, c-format -#| msgid "No such interface `%s'" msgid "No such schema '%s'\n" msgstr "No existe el esquema «%s»\n" @@ -3223,13 +3222,11 @@ msgstr "Se proporcionó una ruta vacía.\n" #: ../gio/gsettings-tool.c:98 #, c-format -#| msgid "a path, if given, must begin and end with a slash" msgid "Path must begin with a slash (/)\n" msgstr "La ruta debe comenzar con una barra (/)\n" #: ../gio/gsettings-tool.c:104 #, c-format -#| msgid "a path, if given, must begin and end with a slash" msgid "Path must end with a slash (/)\n" msgstr "La ruta debe terminar con una barra (/)\n" @@ -3240,76 +3237,69 @@ msgstr "La ruta no debe contener dos barras adyacentes (//)\n" #: ../gio/gsettings-tool.c:131 #, c-format -#| msgid "No such property `%s'" msgid "No such key '%s'\n" msgstr "No existe la clave «%s»\n" -#: ../gio/gsettings-tool.c:426 +#: ../gio/gsettings-tool.c:427 #, c-format msgid "The provided value is outside of the valid range\n" msgstr "El valor proporcionado está fuera del rango válido\n" -#: ../gio/gsettings-tool.c:455 +#: ../gio/gsettings-tool.c:456 msgid "List the installed (non-relocatable) schemas" msgstr "Listar los esquemas instalados (no reubicables)" -#: ../gio/gsettings-tool.c:461 +#: ../gio/gsettings-tool.c:462 msgid "List the installed relocatable schemas" msgstr "Listar los esquemas reubicables instalados" -#: ../gio/gsettings-tool.c:467 +#: ../gio/gsettings-tool.c:468 msgid "Lists the keys in SCHEMA" msgstr "Lista las claves en el ESQUEMA" -#: ../gio/gsettings-tool.c:468 ../gio/gsettings-tool.c:474 -#: ../gio/gsettings-tool.c:480 +#: ../gio/gsettings-tool.c:469 ../gio/gsettings-tool.c:475 +#: ../gio/gsettings-tool.c:481 msgid "SCHEMA[:PATH]" msgstr "ESQUEMA[:RUTA]" -#: ../gio/gsettings-tool.c:473 +#: ../gio/gsettings-tool.c:474 msgid "Lists the children of SCHEMA" msgstr "Lista los hijos del ESQUEMA" -#: ../gio/gsettings-tool.c:479 +#: ../gio/gsettings-tool.c:480 msgid "List keys and values, recursively" msgstr "Listar las claves y valores recursivamente" -#: ../gio/gsettings-tool.c:485 -#| msgid "Get the value of KEY" +#: ../gio/gsettings-tool.c:486 msgid "Gets the value of KEY" msgstr "Obtiene el valor de la CLAVE" -#: ../gio/gsettings-tool.c:486 ../gio/gsettings-tool.c:492 -#: ../gio/gsettings-tool.c:504 ../gio/gsettings-tool.c:510 -#| msgid "SCHEMA KEY" +#: ../gio/gsettings-tool.c:487 ../gio/gsettings-tool.c:493 +#: ../gio/gsettings-tool.c:505 ../gio/gsettings-tool.c:511 msgid "SCHEMA[:PATH] KEY" msgstr "ESQUEMA[:RUTA] CLAVE" -#: ../gio/gsettings-tool.c:491 +#: ../gio/gsettings-tool.c:492 msgid "Queries the range of valid values for KEY" msgstr "Consulta el rango de valores válidos para la CLAVE" -#: ../gio/gsettings-tool.c:497 -#| msgid "Set the value of KEY" +#: ../gio/gsettings-tool.c:498 msgid "Sets the value of KEY to VALUE" msgstr "Establece el valor de la CLAVE a VALOR" -#: ../gio/gsettings-tool.c:498 -#| msgid "SCHEMA KEY VALUE" +#: ../gio/gsettings-tool.c:499 msgid "SCHEMA[:PATH] KEY VALUE" msgstr "ESQUEMA[:RUTA] CLAVE VALOR" -#: ../gio/gsettings-tool.c:503 -#| msgid "Sets KEY to its default value" +#: ../gio/gsettings-tool.c:504 msgid "Resets KEY to its default value" msgstr "Restablece la CLAVE a su valor predeterminado" -#: ../gio/gsettings-tool.c:509 -#| msgid "Find out whether KEY is writable" +#: ../gio/gsettings-tool.c:510 msgid "Checks if KEY is writable" msgstr "Comprueba si la CLAVE se puede escribir" -#: ../gio/gsettings-tool.c:515 +#: ../gio/gsettings-tool.c:516 msgid "" "Monitors KEY for changes.\n" "If no KEY is specified, monitor all keys in SCHEMA.\n" @@ -3319,14 +3309,12 @@ msgstr "" "Si no se especifica una CLAVE, monitoriza todas las claves en el ESQUEMA.\n" "Use ^C para detener la monitorización.\n" -#: ../gio/gsettings-tool.c:518 -#| msgid "SCHEMA KEY" +#: ../gio/gsettings-tool.c:519 msgid "SCHEMA[:PATH] [KEY]" msgstr "ESQUEMA[:RUTA] [CLAVE]" -#: ../gio/gsettings-tool.c:522 +#: ../gio/gsettings-tool.c:523 #, c-format -#| msgid "Unknown command '%s'\n" msgid "" "Unknown command %s\n" "\n" @@ -3334,7 +3322,7 @@ msgstr "" "Comando «%s» desconocido\n" "\n" -#: ../gio/gsettings-tool.c:530 +#: ../gio/gsettings-tool.c:531 msgid "" "Usage:\n" " gsettings COMMAND [ARGS...]\n" @@ -3376,7 +3364,7 @@ msgstr "" "Use «gsettings help COMANDO» para obtener una ayuda detallada.\n" "\n" -#: ../gio/gsettings-tool.c:551 +#: ../gio/gsettings-tool.c:552 #, c-format msgid "" "Usage:\n" @@ -3391,15 +3379,11 @@ msgstr "" "%s\n" "\n" -#: ../gio/gsettings-tool.c:556 +#: ../gio/gsettings-tool.c:557 msgid "Arguments:\n" msgstr "Argumentos:\n" -#: ../gio/gsettings-tool.c:560 -#| msgid "" -#| "Arguments:\n" -#| " SCHEMA The id of the schema\n" -#| " KEY The name of the key\n" +#: ../gio/gsettings-tool.c:561 msgid "" " SCHEMA The name of the schema\n" " PATH The path, for relocatable schemas\n" @@ -3407,140 +3391,140 @@ msgstr "" " SCHEMA El nombre del esquema\n" " RUTA La ruta, para esquemas reubicables\n" -#: ../gio/gsettings-tool.c:565 +#: ../gio/gsettings-tool.c:566 msgid " KEY The (optional) key within the schema\n" msgstr " CLAVE La clave (opcional) para el esquema\n" -#: ../gio/gsettings-tool.c:569 +#: ../gio/gsettings-tool.c:570 msgid " KEY The key within the schema\n" msgstr " CLAVE La clave para el esquema\n" -#: ../gio/gsettings-tool.c:573 +#: ../gio/gsettings-tool.c:574 msgid " VALUE The value to set\n" msgstr " VALOR El valor para establecer\n" -#: ../gio/gsettings-tool.c:649 +#: ../gio/gsettings-tool.c:650 #, c-format msgid "Empty schema name given" msgstr "Se proporcionó un nombre de esquema vacío" -#: ../gio/gsocket.c:276 +#: ../gio/gsocket.c:277 msgid "Invalid socket, not initialized" msgstr "Socket no válido, no inicializado" -#: ../gio/gsocket.c:283 +#: ../gio/gsocket.c:284 #, c-format msgid "Invalid socket, initialization failed due to: %s" msgstr "Socket no válido, falló la instalación debido a: %s" -#: ../gio/gsocket.c:291 +#: ../gio/gsocket.c:292 msgid "Socket is already closed" msgstr "El socket ya está cerrado" -#: ../gio/gsocket.c:299 ../gio/gsocket.c:2737 ../gio/gsocket.c:2781 +#: ../gio/gsocket.c:300 ../gio/gsocket.c:2765 ../gio/gsocket.c:2809 msgid "Socket I/O timed out" msgstr "Expiró la E/S del socket" -#: ../gio/gsocket.c:442 +#: ../gio/gsocket.c:443 #, c-format msgid "creating GSocket from fd: %s" msgstr "creando el GSocket desde fd: %s" -#: ../gio/gsocket.c:476 ../gio/gsocket.c:492 ../gio/gsocket.c:2134 +#: ../gio/gsocket.c:477 ../gio/gsocket.c:493 ../gio/gsocket.c:2135 #, c-format msgid "Unable to create socket: %s" msgstr "No se pudo crear el socket: %s" -#: ../gio/gsocket.c:476 +#: ../gio/gsocket.c:477 msgid "Unknown protocol was specified" msgstr "Se especificó un protocolo desconocido" -#: ../gio/gsocket.c:1245 +#: ../gio/gsocket.c:1246 #, c-format msgid "could not get local address: %s" msgstr "no se pudo obtener la dirección local: %s" -#: ../gio/gsocket.c:1288 +#: ../gio/gsocket.c:1289 #, c-format msgid "could not get remote address: %s" msgstr "no se pudo obtener la dirección remota: %s" -#: ../gio/gsocket.c:1349 +#: ../gio/gsocket.c:1350 #, c-format msgid "could not listen: %s" msgstr "no se pudo escuchar: %s" -#: ../gio/gsocket.c:1423 +#: ../gio/gsocket.c:1424 #, c-format msgid "Error binding to address: %s" msgstr "Error al vincular con la dirección: %s" -#: ../gio/gsocket.c:1543 +#: ../gio/gsocket.c:1544 #, c-format msgid "Error accepting connection: %s" msgstr "Error al aceptar la conexión: %s" -#: ../gio/gsocket.c:1660 +#: ../gio/gsocket.c:1661 msgid "Error connecting: " msgstr "Error al conectar: " -#: ../gio/gsocket.c:1665 +#: ../gio/gsocket.c:1666 msgid "Connection in progress" msgstr "Conexión en progreso" -#: ../gio/gsocket.c:1672 +#: ../gio/gsocket.c:1673 #, c-format msgid "Error connecting: %s" msgstr "Error al conectar: %s" -#: ../gio/gsocket.c:1715 ../gio/gsocket.c:3500 +#: ../gio/gsocket.c:1716 ../gio/gsocket.c:3528 #, c-format msgid "Unable to get pending error: %s" msgstr "No se pudo obtener el error pendiente: %s" -#: ../gio/gsocket.c:1847 +#: ../gio/gsocket.c:1848 #, c-format msgid "Error receiving data: %s" msgstr "Error al recibir los datos: %s" -#: ../gio/gsocket.c:2021 +#: ../gio/gsocket.c:2022 #, c-format msgid "Error sending data: %s" msgstr "Error al enviar los datos: %s" -#: ../gio/gsocket.c:2213 +#: ../gio/gsocket.c:2214 #, c-format msgid "Error closing socket: %s" msgstr "Error al cerrar el socket: %s" -#: ../gio/gsocket.c:2730 +#: ../gio/gsocket.c:2758 #, c-format msgid "Waiting for socket condition: %s" msgstr "Esperando la condición del socket: %s" -#: ../gio/gsocket.c:3020 +#: ../gio/gsocket.c:3048 msgid "GSocketControlMessage not supported on windows" msgstr "GSocketControlMessage no está soportado en win32" -#: ../gio/gsocket.c:3279 ../gio/gsocket.c:3420 +#: ../gio/gsocket.c:3307 ../gio/gsocket.c:3448 #, c-format msgid "Error receiving message: %s" msgstr "Error al recibir el mensaje: %s" -#: ../gio/gsocket.c:3515 +#: ../gio/gsocket.c:3543 msgid "g_socket_get_credentials not implemented for this OS" msgstr "g_socket_get_credentials no está implementado en este SO" -#: ../gio/gsocketclient.c:674 ../gio/gsocketclient.c:1153 +#: ../gio/gsocketclient.c:798 ../gio/gsocketclient.c:1364 msgid "Unknown error on connect" msgstr "Error desconocido al conectar" -#: ../gio/gsocketclient.c:711 ../gio/gsocketclient.c:1038 +#: ../gio/gsocketclient.c:836 ../gio/gsocketclient.c:1248 msgid "Trying to proxy over non-TCP connection is not supported." msgstr "" "No se soporta intentar hacer de proxy sobre una conexión que no es TCP." -#: ../gio/gsocketclient.c:749 ../gio/gsocketclient.c:1061 +#: ../gio/gsocketclient.c:858 ../gio/gsocketclient.c:1273 #, c-format msgid "Proxy protocol '%s' is not supported." msgstr "El protocolo del proxy «%s» no está soportado." @@ -3589,7 +3573,8 @@ msgstr "El servidor proxy SOCKSv5 requiere autenticación." #: ../gio/gsocks5proxy.c:179 msgid "" -"The SOCKSv5 proxy requires an authentication method that is not supported by GLib." +"The SOCKSv5 proxy requires an authentication method that is not supported by " +"GLib." msgstr "" "El servidor SOCKSv5 requiere un método de autenticación que GLib no soporta." @@ -3654,6 +3639,18 @@ msgstr "Error desconocido del servidor proxy SOCKSv5." msgid "Can't handle version %d of GThemedIcon encoding" msgstr "No se puede manejar la versión %d de la codificación GThemedIcon" +#: ../gio/gtlscertificate.c:270 +msgid "No PEM-encoded certificate found" +msgstr "No se encontró ningún certificado codificado con PEM" + +#: ../gio/gtlscertificate.c:279 +msgid "Could not parse PEM-encoded certificate" +msgstr "No se pudo analizar el certificado codificado con PEM" + +#: ../gio/gtlscertificate.c:300 +msgid "Could not parse PEM-encoded private key" +msgstr "No se pudo analizar la clave privada codificada con PEM" + #: ../gio/gunixconnection.c:164 ../gio/gunixconnection.c:505 #, c-format msgid "Expecting 1 control message, got %d" @@ -3707,14 +3704,14 @@ msgstr "" msgid "Error while disabling SO_PASSCRED: %s" msgstr "Error al desactivar SO_PASSCRED: %s" -#: ../gio/gunixinputstream.c:353 ../gio/gunixinputstream.c:373 -#: ../gio/gunixinputstream.c:451 +#: ../gio/gunixinputstream.c:368 ../gio/gunixinputstream.c:388 +#: ../gio/gunixinputstream.c:466 #, c-format msgid "Error reading from unix: %s" msgstr "Error al leer de unix: %s" -#: ../gio/gunixinputstream.c:406 ../gio/gunixinputstream.c:589 -#: ../gio/gunixoutputstream.c:393 ../gio/gunixoutputstream.c:545 +#: ../gio/gunixinputstream.c:421 ../gio/gunixinputstream.c:601 +#: ../gio/gunixoutputstream.c:407 ../gio/gunixoutputstream.c:556 #, c-format msgid "Error closing unix: %s" msgstr "Error al cerrar unix: %s" @@ -3723,8 +3720,8 @@ msgstr "Error al cerrar unix: %s" msgid "Filesystem root" msgstr "Sistema de archivos raíz" -#: ../gio/gunixoutputstream.c:339 ../gio/gunixoutputstream.c:360 -#: ../gio/gunixoutputstream.c:438 +#: ../gio/gunixoutputstream.c:353 ../gio/gunixoutputstream.c:374 +#: ../gio/gunixoutputstream.c:452 #, c-format msgid "Error writing to unix: %s" msgstr "Error al escribir en unix: %s" From beec9743eba6013229befafdfe120cd7701d5214 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Tue, 30 Nov 2010 23:04:17 +0000 Subject: [PATCH 42/44] gmain: Add Since: 2.28 tag to g_source_{add,remove}_child_source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New API should have gtk-doc tags to document the version it was introduced. Signed-off-by: Javier Jardón --- glib/gmain.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/glib/gmain.c b/glib/gmain.c index b02606795..d0e7f1768 100644 --- a/glib/gmain.c +++ b/glib/gmain.c @@ -1194,6 +1194,8 @@ g_source_remove_poll (GSource *source, * * @source will hold a reference on @child_source while @child_source * is attached to it. + * + * Since: 2.28 **/ void g_source_add_child_source (GSource *source, @@ -1237,6 +1239,8 @@ g_source_add_child_source (GSource *source, * g_source_add_child_source(). * * Detaches @child_source from @source and destroys it. + * + * Since: 2.28 **/ void g_source_remove_child_source (GSource *source, From 9fe7fd9120940a2d50ff660f1a3cf7efd08ac01b Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Tue, 30 Nov 2010 18:19:12 -0600 Subject: [PATCH 43/44] Bug 636100 - Can't read GSettings:backend property The PROP_BACKEND case was missing from the switch statement in g_settings_get_property(). --- gio/gsettings.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gio/gsettings.c b/gio/gsettings.c index 8c3bd72d2..d88ad015c 100644 --- a/gio/gsettings.c +++ b/gio/gsettings.c @@ -435,6 +435,10 @@ g_settings_get_property (GObject *object, g_value_set_string (value, settings->priv->schema_name); break; + case PROP_BACKEND: + g_value_set_object (value, settings->priv->backend); + break; + case PROP_PATH: g_value_set_string (value, settings->priv->path); break; From 3e61cb2fcc7648254192d0f174b437336b21c89b Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Thu, 2 Dec 2010 16:59:22 +0000 Subject: [PATCH 44/44] Fix typo in API docs for GDateTime s/monty/month/ --- glib/gdatetime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/glib/gdatetime.c b/glib/gdatetime.c index 5608a59a2..7f8359119 100644 --- a/glib/gdatetime.c +++ b/glib/gdatetime.c @@ -1409,7 +1409,7 @@ g_date_time_equal (gconstpointer dt1, * g_date_time_get_ymd: * @datetime: a #GDateTime. * @year: (out): the return location for the gregorian year, or %NULL. - * @month: (out): the return location for the monty of the year, or %NULL. + * @month: (out): the return location for the month of the year, or %NULL. * @day: (out): the return location for the day of the month, or %NULL. * * Retrieves the Gregorian day, month, and year of a given #GDateTime.