]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - tests/src/x-server.c
Refactored code to replace hardcoded signal identification strings by constants.
[sojka/lightdm.git] / tests / src / x-server.c
1 /* -*- Mode: C; indent-tabs-mode: nil; tab-width: 4 -*- */
2
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <errno.h>
7 #include <sys/types.h>
8 #include <sys/socket.h>
9 #include <glib.h>
10 #include <gio/gio.h>
11 #include <gio/gunixsocketaddress.h>
12
13 #include "x-server.h"
14
15 G_DEFINE_TYPE (XServer, x_server, G_TYPE_OBJECT);
16 G_DEFINE_TYPE (XClient, x_client, G_TYPE_OBJECT);
17
18 #define MAXIMUM_REQUEST_LENGTH 65535
19
20 enum {
21     X_SERVER_CLIENT_CONNECTED,
22     X_SERVER_CLIENT_DISCONNECTED,
23     X_SERVER_LAST_SIGNAL
24 };
25 static guint x_server_signals[X_SERVER_LAST_SIGNAL] = { 0 };
26
27 struct XServerPrivate
28 {
29     gint display_number;
30
31     gchar *socket_path;
32     GSocket *socket;
33     GIOChannel *channel;
34     GHashTable *clients;
35 };
36
37 struct XClientPrivate
38 {
39     XServer *server;
40     GSocket *socket;
41     GIOChannel *channel;
42 };
43
44 enum
45 {
46     X_CLIENT_DISCONNECTED,
47     X_CLIENT_LAST_SIGNAL
48 };
49 static guint x_client_signals[X_CLIENT_LAST_SIGNAL] = { 0 };
50
51 void
52 x_client_send_failed (XClient *client, const gchar *reason)
53 {
54     gchar *message;
55
56     message = g_strdup_printf ("FAILED:%s", reason);
57     errno = 0;
58     if (send (g_io_channel_unix_get_fd (client->priv->channel), message, strlen (message), 0) != strlen (message))
59         g_printerr ("Failed to send FAILED: %s\n", strerror (errno));
60     g_free (message);
61 }
62
63 void
64 x_client_send_success (XClient *client)
65 {
66     gchar *message;
67
68     message = g_strdup ("SUCCESS");
69     errno = 0;
70     if (send (g_io_channel_unix_get_fd (client->priv->channel), message, strlen (message), 0) != strlen (message))
71         g_printerr ("Failed to send SUCCESS: %s\n", strerror (errno));
72     g_free (message);
73 }
74
75 void
76 x_client_disconnect (XClient *client)
77 {
78     g_io_channel_shutdown (client->priv->channel, TRUE, NULL);
79 }
80
81 static void
82 x_client_init (XClient *client)
83 {
84     client->priv = G_TYPE_INSTANCE_GET_PRIVATE (client, x_client_get_type (), XClientPrivate);
85 }
86
87 static void
88 x_client_class_init (XClientClass *klass)
89 {
90     g_type_class_add_private (klass, sizeof (XClientPrivate));
91
92     x_client_signals[X_CLIENT_DISCONNECTED] =
93         g_signal_new (X_CLIENT_SIGNAL_DISCONNECTED,
94                       G_TYPE_FROM_CLASS (klass),
95                       G_SIGNAL_RUN_LAST,
96                       G_STRUCT_OFFSET (XClientClass, disconnected),
97                       NULL, NULL,
98                       NULL,
99                       G_TYPE_NONE, 0);
100 }
101
102 XServer *
103 x_server_new (gint display_number)
104 {
105     XServer *server = g_object_new (x_server_get_type (), NULL);
106     server->priv->display_number = display_number;
107     return server;
108 }
109
110 static void
111 x_client_disconnected_cb (XClient *client, XServer *server)
112 {
113     g_signal_handlers_disconnect_matched (client, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, server);
114     g_hash_table_remove (server->priv->clients, client->priv->channel);
115     g_signal_emit (server, x_server_signals[X_SERVER_CLIENT_DISCONNECTED], 0, client);
116 }
117
118 static gboolean
119 socket_connect_cb (GIOChannel *channel, GIOCondition condition, gpointer data)
120 {
121     XServer *server = data;
122     GSocket *data_socket;
123     XClient *client;
124     GError *error = NULL;
125
126     data_socket = g_socket_accept (server->priv->socket, NULL, &error);
127     if (error)
128         g_warning ("Error accepting connection: %s", strerror (errno));
129     g_clear_error (&error);
130     if (!data_socket)
131         return FALSE;
132
133     client = g_object_new (x_client_get_type (), NULL);
134     client->priv->server = server;
135     g_signal_connect (client, X_CLIENT_SIGNAL_DISCONNECTED, G_CALLBACK (x_client_disconnected_cb), server);
136     client->priv->socket = data_socket;
137     client->priv->channel = g_io_channel_unix_new (g_socket_get_fd (data_socket));
138     g_hash_table_insert (server->priv->clients, client->priv->channel, client);
139
140     g_signal_emit (server, x_server_signals[X_SERVER_CLIENT_CONNECTED], 0, client);
141
142     return TRUE;
143 }
144
145 gboolean
146 x_server_start (XServer *server)
147 {
148     gchar *name;
149     GError *error = NULL;
150
151     name = g_strdup_printf (".x:%d", server->priv->display_number);
152     server->priv->socket_path = g_build_filename (g_getenv ("LIGHTDM_TEST_ROOT"), name, NULL);
153     g_free (name);
154
155     server->priv->socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, &error);
156     if (!server->priv->socket ||
157         !g_socket_bind (server->priv->socket, g_unix_socket_address_new (server->priv->socket_path), TRUE, &error) ||
158         !g_socket_listen (server->priv->socket, &error))
159     {
160         g_warning ("Error creating Unix X socket: %s", error->message);
161         return FALSE;
162     }
163     server->priv->channel = g_io_channel_unix_new (g_socket_get_fd (server->priv->socket));
164     g_io_add_watch (server->priv->channel, G_IO_IN, socket_connect_cb, server);
165
166     return TRUE;
167 }
168
169 gsize
170 x_server_get_n_clients (XServer *server)
171 {
172     return g_hash_table_size (server->priv->clients);
173 }
174
175 static void
176 x_server_init (XServer *server)
177 {
178     server->priv = G_TYPE_INSTANCE_GET_PRIVATE (server, x_server_get_type (), XServerPrivate);
179     server->priv->clients = g_hash_table_new_full (g_direct_hash, g_direct_equal, (GDestroyNotify) g_io_channel_unref, g_object_unref);
180 }
181
182 static void
183 x_server_finalize (GObject *object)
184 {
185     XServer *server = (XServer *) object;
186     if (server->priv->socket_path)
187         unlink (server->priv->socket_path);
188     G_OBJECT_CLASS (x_server_parent_class)->finalize (object);
189 }
190
191 static void
192 x_server_class_init (XServerClass *klass)
193 {
194     GObjectClass *object_class = G_OBJECT_CLASS (klass);
195     object_class->finalize = x_server_finalize;
196     g_type_class_add_private (klass, sizeof (XServerPrivate));
197     x_server_signals[X_SERVER_CLIENT_CONNECTED] =
198         g_signal_new (X_SERVER_SIGNAL_CLIENT_CONNECTED,
199                       G_TYPE_FROM_CLASS (klass),
200                       G_SIGNAL_RUN_LAST,
201                       G_STRUCT_OFFSET (XServerClass, client_connected),
202                       NULL, NULL,
203                       NULL,
204                       G_TYPE_NONE, 1, x_client_get_type ());
205     x_server_signals[X_SERVER_CLIENT_DISCONNECTED] =
206         g_signal_new (X_SERVER_SIGNAL_CLIENT_DISCONNECTED,
207                       G_TYPE_FROM_CLASS (klass),
208                       G_SIGNAL_RUN_LAST,
209                       G_STRUCT_OFFSET (XServerClass, client_disconnected),
210                       NULL, NULL,
211                       NULL,
212                       G_TYPE_NONE, 1, x_client_get_type ());
213 }