[kdbus] KDBUS_ITEM_PAYLOAD_OFF items are (once again) relative to msg header
[platform/upstream/glib.git] / gio / tests / socket-listener.c
1 /* GLib testing framework examples and tests
2  *
3  * Copyright 2014 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, see
17  * <http://www.gnu.org/licenses/>.
18  */
19
20 #include <gio/gio.h>
21
22 GMutex mutex_712570;
23 GCond cond_712570;
24 volatile gboolean finalized;
25
26 GType test_threaded_socket_service_get_type (void);
27 typedef GThreadedSocketService TestThreadedSocketService;
28 typedef GThreadedSocketServiceClass TestThreadedSocketServiceClass;
29
30 G_DEFINE_TYPE (TestThreadedSocketService, test_threaded_socket_service, G_TYPE_THREADED_SOCKET_SERVICE);
31
32 static void
33 test_threaded_socket_service_init (TestThreadedSocketService *service)
34 {
35 }
36
37 static void
38 test_threaded_socket_service_finalize (GObject *object)
39 {
40   G_OBJECT_CLASS (test_threaded_socket_service_parent_class)->finalize (object);
41
42   /* Signal the main thread that finalization completed successfully
43    * rather than hanging.
44    */
45   finalized = TRUE;
46   g_cond_signal (&cond_712570);
47   g_mutex_unlock (&mutex_712570);
48 }
49
50 static void
51 test_threaded_socket_service_class_init (TestThreadedSocketServiceClass *klass)
52 {
53   GObjectClass *object_class = G_OBJECT_CLASS (klass);
54
55   object_class->finalize = test_threaded_socket_service_finalize;
56 }
57
58 static gboolean
59 connection_cb (GThreadedSocketService *service,
60                GSocketConnection      *connection,
61                GObject                *source_object,
62                gpointer                user_data)
63 {
64   /* Block until the main thread has dropped its ref to @service, so that we
65    * will drop the final ref from this thread.
66    */
67   g_mutex_lock (&mutex_712570);
68
69   /* The service should now have 1 ref owned by the current "run"
70    * signal emission, and another added by GThreadedSocketService for
71    * this thread. Both will be dropped after we return.
72    */
73   g_assert_cmpint (G_OBJECT (service)->ref_count, ==, 2);
74
75   return FALSE;
76 }
77
78 static void
79 client_connected_cb (GObject      *client,
80                      GAsyncResult *result,
81                      gpointer      user_data)
82 {
83   GMainLoop *loop = user_data;
84   GSocketConnection *conn;
85   GError *error = NULL;
86
87   conn = g_socket_client_connect_finish (G_SOCKET_CLIENT (client), result, &error);
88   g_assert_no_error (error);
89
90   g_object_unref (conn);
91   g_main_loop_quit (loop);
92 }
93
94 static void
95 test_threaded_712570 (void)
96 {
97   GSocketService *service;
98   GSocketAddress *addr, *listening_addr;
99   GMainLoop *loop;
100   GSocketClient *client;
101   GError *error = NULL;
102   int ref_count;
103
104   g_test_bug ("712570");
105
106   g_mutex_lock (&mutex_712570);
107
108   service = g_object_new (test_threaded_socket_service_get_type (), NULL);
109
110   addr = g_inet_socket_address_new_from_string ("127.0.0.1", 0);
111   g_socket_listener_add_address (G_SOCKET_LISTENER (service),
112                                  addr,
113                                  G_SOCKET_TYPE_STREAM,
114                                  G_SOCKET_PROTOCOL_TCP,
115                                  NULL,
116                                  &listening_addr,
117                                  &error);
118   g_assert_no_error (error);
119   g_object_unref (addr);
120
121   g_signal_connect (service, "run", G_CALLBACK (connection_cb), NULL);
122
123   loop = g_main_loop_new (NULL, FALSE);
124
125   client = g_socket_client_new ();
126   g_socket_client_connect_async (client,
127                                  G_SOCKET_CONNECTABLE (listening_addr),
128                                  NULL,
129                                  client_connected_cb, loop);
130   g_object_unref (client);
131   g_object_unref (listening_addr);
132
133   g_main_loop_run (loop);
134   g_main_loop_unref (loop);
135
136   /* Stop the service and then wait for it to asynchronously cancel
137    * its outstanding accept() call (and drop the associated ref).
138    */
139   ref_count = G_OBJECT (service)->ref_count;
140   g_socket_service_stop (G_SOCKET_SERVICE (service));
141   while (G_OBJECT (service)->ref_count == ref_count)
142     g_main_context_iteration (NULL, TRUE);
143
144   /* Drop our ref, then unlock the mutex and wait for the service to be
145    * finalized. (Without the fix for 712570 it would hang forever here.)
146    */
147   g_object_unref (service);
148
149   while (!finalized)
150     g_cond_wait (&cond_712570, &mutex_712570);
151   g_mutex_unlock (&mutex_712570);
152 }
153
154 int
155 main (int   argc,
156       char *argv[])
157 {
158   g_test_init (&argc, &argv, NULL);
159
160   g_test_bug_base ("http://bugzilla.gnome.org/");
161
162   g_test_add_func ("/socket-listener/threaded/712570", test_threaded_712570);
163
164   return g_test_run();
165 }
166