From: Paolo Borelli Date: Fri, 10 Jul 2015 19:30:28 +0000 (+0200) Subject: socketservice: add an "active" property X-Git-Tag: 2.45.4~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=e1d44799c0ba87506873c309ad4e16cce13bbfc4;p=platform%2Fupstream%2Fglib.git socketservice: add an "active" property We already have start, stop and is_active methods, but turning it into a real property is useful for a few reasons: - it allows us to bind the property to an UI or a setting - it allows us to get notified when the state changes - it allows us to instantiate objects directly in the stopped state https://bugzilla.gnome.org/show_bug.cgi?id=752089 --- diff --git a/gio/gsocketservice.c b/gio/gsocketservice.c index 81053f0..89bc728 100644 --- a/gio/gsocketservice.c +++ b/gio/gsocketservice.c @@ -63,6 +63,7 @@ #include #include "gsocketlistener.h" #include "gsocketconnection.h" +#include "glibintl.h" struct _GSocketServicePrivate { @@ -77,6 +78,12 @@ G_LOCK_DEFINE_STATIC(active); G_DEFINE_TYPE_WITH_PRIVATE (GSocketService, g_socket_service, G_TYPE_SOCKET_LISTENER) +enum +{ + PROP_0, + PROP_ACTIVE +}; + static void g_socket_service_ready (GObject *object, GAsyncResult *result, gpointer user_data); @@ -117,6 +124,90 @@ do_accept (GSocketService *service) service->priv->outstanding_accept = TRUE; } +static gboolean +get_active (GSocketService *service) +{ + gboolean active; + + G_LOCK (active); + active = service->priv->active; + G_UNLOCK (active); + + return active; +} + +static void +set_active (GSocketService *service, gboolean active) +{ + gboolean notify = FALSE; + + active = !!active; + + G_LOCK (active); + + if (active != service->priv->active) + { + service->priv->active = active; + notify = TRUE; + + if (active) + { + if (service->priv->outstanding_accept) + g_cancellable_cancel (service->priv->cancellable); + else + do_accept (service); + } + else + { + if (service->priv->outstanding_accept) + g_cancellable_cancel (service->priv->cancellable); + } + } + + G_UNLOCK (active); + + if (notify) + g_object_notify (G_OBJECT (service), "active"); +} + +static void +g_socket_service_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GSocketService *service = G_SOCKET_SERVICE (object); + + switch (prop_id) + { + case PROP_ACTIVE: + g_value_set_boolean (value, get_active (service)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +g_socket_service_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GSocketService *service = G_SOCKET_SERVICE (object); + + switch (prop_id) + { + case PROP_ACTIVE: + set_active (service, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + static void g_socket_service_changed (GSocketListener *listener) { @@ -151,12 +242,9 @@ g_socket_service_changed (GSocketListener *listener) gboolean g_socket_service_is_active (GSocketService *service) { - gboolean active; + g_return_val_if_fail (G_IS_SOCKET_SERVICE (service), FALSE); - G_LOCK (active); - active = service->priv->active; - G_UNLOCK (active); - return active; + return get_active (service); } /** @@ -174,19 +262,9 @@ g_socket_service_is_active (GSocketService *service) void g_socket_service_start (GSocketService *service) { - G_LOCK (active); + g_return_if_fail (G_IS_SOCKET_SERVICE (service)); - if (!service->priv->active) - { - service->priv->active = TRUE; - - if (service->priv->outstanding_accept) - g_cancellable_cancel (service->priv->cancellable); - else - do_accept (service); - } - - G_UNLOCK (active); + set_active (service, TRUE); } /** @@ -210,20 +288,11 @@ g_socket_service_start (GSocketService *service) void g_socket_service_stop (GSocketService *service) { - G_LOCK (active); - - if (service->priv->active) - { - service->priv->active = FALSE; - - if (service->priv->outstanding_accept) - g_cancellable_cancel (service->priv->cancellable); - } + g_return_if_fail (G_IS_SOCKET_SERVICE (service)); - G_UNLOCK (active); + set_active (service, FALSE); } - static gboolean g_socket_service_incoming (GSocketService *service, GSocketConnection *connection, @@ -243,6 +312,8 @@ g_socket_service_class_init (GSocketServiceClass *class) GSocketListenerClass *listener_class = G_SOCKET_LISTENER_CLASS (class); gobject_class->finalize = g_socket_service_finalize; + gobject_class->set_property = g_socket_service_set_property; + gobject_class->get_property = g_socket_service_get_property; listener_class->changed = g_socket_service_changed; class->incoming = g_socket_service_real_incoming; @@ -271,6 +342,20 @@ g_socket_service_class_init (GSocketServiceClass *class) g_signal_accumulator_true_handled, NULL, NULL, G_TYPE_BOOLEAN, 2, G_TYPE_SOCKET_CONNECTION, G_TYPE_OBJECT); + + /** + * GSocketService:active: + * + * Whether the service is currently accepting connections. + * + * Since: 2.46 + */ + g_object_class_install_property (gobject_class, PROP_ACTIVE, + g_param_spec_boolean ("active", + P_("Active"), + P_("Whether the service is currently accepting connections"), + TRUE, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } static void @@ -309,7 +394,6 @@ g_socket_service_ready (GObject *object, G_UNLOCK (active); } - /** * g_socket_service_new: * diff --git a/gio/tests/.gitignore b/gio/tests/.gitignore index 3a8dd04..7ad7ba0 100644 --- a/gio/tests/.gitignore +++ b/gio/tests/.gitignore @@ -120,6 +120,7 @@ socket socket-address socket-client socket-listener +socket-service socket-server srvtarget task diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am index 135f877..143055a 100644 --- a/gio/tests/Makefile.am +++ b/gio/tests/Makefile.am @@ -57,6 +57,7 @@ test_programs = \ sleepy-stream \ socket \ socket-listener \ + socket-service \ srvtarget \ task \ tls-interaction \ diff --git a/gio/tests/socket-service.c b/gio/tests/socket-service.c new file mode 100644 index 0000000..cb9f6bd --- /dev/null +++ b/gio/tests/socket-service.c @@ -0,0 +1,111 @@ +/* GLib testing framework examples and tests + * + * Copyright 2014 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, see + * . + */ + +#include + +static void +active_notify_cb (GSocketService *service, + GParamSpec *pspec, + gpointer data) +{ + gboolean *success = (gboolean *)data; + + if (g_socket_service_is_active (service)) + *success = TRUE; +} + +static void +connected_cb (GObject *client, + GAsyncResult *result, + gpointer user_data) +{ + GSocketService *service = G_SOCKET_SERVICE (user_data); + GSocketConnection *conn; + GError *error = NULL; + + g_assert_true (g_socket_service_is_active (service)); + + conn = g_socket_client_connect_finish (G_SOCKET_CLIENT (client), result, &error); + g_assert_no_error (error); + g_object_unref (conn); + + g_socket_service_stop (service); + g_assert_false (g_socket_service_is_active (service)); +} + +static void +test_start_stop (void) +{ + gboolean success = FALSE; + GInetAddress *iaddr; + GSocketAddress *saddr, *listening_addr; + GSocketService *service; + GError *error = NULL; + GSocketClient *client; + + iaddr = g_inet_address_new_loopback (G_SOCKET_FAMILY_IPV4); + saddr = g_inet_socket_address_new (iaddr, 0); + g_object_unref (iaddr); + + /* instanciate with g_object_new so we can pass active = false */ + service = g_object_new (G_TYPE_SOCKET_SERVICE, "active", FALSE, NULL); + g_assert_false (g_socket_service_is_active (service)); + + g_signal_connect (service, "notify::active", G_CALLBACK (active_notify_cb), &success); + + g_socket_listener_add_address (G_SOCKET_LISTENER (service), + saddr, + G_SOCKET_TYPE_STREAM, + G_SOCKET_PROTOCOL_TCP, + NULL, + &listening_addr, + &error); + g_assert_no_error (error); + g_object_unref (saddr); + + client = g_socket_client_new (); + g_socket_client_connect_async (client, + G_SOCKET_CONNECTABLE (listening_addr), + NULL, + connected_cb, service); + g_object_unref (client); + g_object_unref (listening_addr); + + g_socket_service_start (service); + g_assert_true (g_socket_service_is_active (service)); + + do + g_main_context_iteration (NULL, TRUE); + while (!success); + + g_object_unref (service); +} + +int +main (int argc, + char *argv[]) +{ + g_test_init (&argc, &argv, NULL); + + g_test_bug_base ("http://bugzilla.gnome.org/"); + + g_test_add_func ("/socket-service/start-stop", test_start_stop); + + return g_test_run(); +}