1 /* -*- Mode: C; indent-tabs-mode: nil; tab-width: 4 -*- */
8 #include <sys/socket.h>
11 #include <gio/gunixsocketaddress.h>
15 G_DEFINE_TYPE (XServer, x_server, G_TYPE_OBJECT);
16 G_DEFINE_TYPE (XClient, x_client, G_TYPE_OBJECT);
18 #define MAXIMUM_REQUEST_LENGTH 65535
21 X_SERVER_CLIENT_CONNECTED,
22 X_SERVER_CLIENT_DISCONNECTED,
25 static guint x_server_signals[X_SERVER_LAST_SIGNAL] = { 0 };
46 X_CLIENT_DISCONNECTED,
49 static guint x_client_signals[X_CLIENT_LAST_SIGNAL] = { 0 };
52 x_client_send_failed (XClient *client, const gchar *reason)
56 message = g_strdup_printf ("FAILED:%s", reason);
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));
64 x_client_send_success (XClient *client)
68 message = g_strdup ("SUCCESS");
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));
76 x_client_disconnect (XClient *client)
78 g_io_channel_shutdown (client->priv->channel, TRUE, NULL);
82 x_client_init (XClient *client)
84 client->priv = G_TYPE_INSTANCE_GET_PRIVATE (client, x_client_get_type (), XClientPrivate);
88 x_client_class_init (XClientClass *klass)
90 g_type_class_add_private (klass, sizeof (XClientPrivate));
92 x_client_signals[X_CLIENT_DISCONNECTED] =
93 g_signal_new (X_CLIENT_SIGNAL_DISCONNECTED,
94 G_TYPE_FROM_CLASS (klass),
96 G_STRUCT_OFFSET (XClientClass, disconnected),
103 x_server_new (gint display_number)
105 XServer *server = g_object_new (x_server_get_type (), NULL);
106 server->priv->display_number = display_number;
111 x_client_disconnected_cb (XClient *client, XServer *server)
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);
119 socket_connect_cb (GIOChannel *channel, GIOCondition condition, gpointer data)
121 XServer *server = data;
122 GSocket *data_socket;
124 GError *error = NULL;
126 data_socket = g_socket_accept (server->priv->socket, NULL, &error);
128 g_warning ("Error accepting connection: %s", strerror (errno));
129 g_clear_error (&error);
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);
140 g_signal_emit (server, x_server_signals[X_SERVER_CLIENT_CONNECTED], 0, client);
146 x_server_start (XServer *server)
149 GError *error = NULL;
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);
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))
160 g_warning ("Error creating Unix X socket: %s", error->message);
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);
170 x_server_get_n_clients (XServer *server)
172 return g_hash_table_size (server->priv->clients);
176 x_server_init (XServer *server)
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);
183 x_server_finalize (GObject *object)
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);
192 x_server_class_init (XServerClass *klass)
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),
201 G_STRUCT_OFFSET (XServerClass, client_connected),
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),
209 G_STRUCT_OFFSET (XServerClass, client_disconnected),
212 G_TYPE_NONE, 1, x_client_get_type ());