summaryrefslogtreecommitdiff
path: root/liblightdm-gobject/greeter.c
diff options
context:
space:
mode:
authorRobert Ancell <robert.ancell@canonical.com>2014-04-29 10:46:22 +1200
committerRobert Ancell <robert.ancell@canonical.com>2014-04-29 10:46:22 +1200
commit2a6a03316d2260d893396b94297574a5593cee90 (patch)
treee8738b9eb84f0b7cc445bf0fb694e30ddf7e42b6 /liblightdm-gobject/greeter.c
parentce49f5ad56827f1355b71e0d5d77c0edafe29da7 (diff)
parenta40c2a24a4d3ef2285f0af78de7b43ce7766a1cf (diff)
downloadlightdm-git-2a6a03316d2260d893396b94297574a5593cee90.tar.gz
Handle unexpected messages during synchronous calls. This is taken from an unfinished asynchronous call branch.
Diffstat (limited to 'liblightdm-gobject/greeter.c')
-rw-r--r--liblightdm-gobject/greeter.c347
1 files changed, 243 insertions, 104 deletions
diff --git a/liblightdm-gobject/greeter.c b/liblightdm-gobject/greeter.c
index 385ffaa8..fe67fc4a 100644
--- a/liblightdm-gobject/greeter.c
+++ b/liblightdm-gobject/greeter.c
@@ -57,6 +57,10 @@ typedef struct
gsize n_responses_waiting;
GList *responses_received;
+ GList *connect_requests;
+ GList *start_session_requests;
+ GList *ensure_shared_data_dir_requests;
+
GHashTable *hints;
guint autologin_timeout;
@@ -100,6 +104,22 @@ typedef enum
SERVER_MESSAGE_RESET,
} ServerMessage;
+/* Request sent to server */
+typedef struct
+{
+ GObject parent_instance;
+ gboolean complete;
+ guint32 return_code;
+ gchar *dir;
+} Request;
+typedef struct
+{
+ GObjectClass parent_class;
+} RequestClass;
+GType request_get_type (void);
+#define REQUEST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), request_get_type (), Request))
+G_DEFINE_TYPE (Request, request, G_TYPE_OBJECT);
+
/**
* lightdm_greeter_new:
*
@@ -134,6 +154,16 @@ lightdm_greeter_set_resettable (LightDMGreeter *greeter, gboolean resettable)
priv->resettable = resettable;
}
+static Request *
+request_new (void)
+{
+ Request *request;
+
+ request = g_object_new (request_get_type (), NULL);
+
+ return request;
+}
+
static gboolean
timed_login_cb (gpointer data)
{
@@ -277,6 +307,7 @@ handle_connected (LightDMGreeter *greeter, guint8 *message, gsize message_length
gchar *version;
GString *hint_string;
int timeout;
+ Request *request;
version = read_string (message, message_length, offset);
hint_string = g_string_new ("");
@@ -290,6 +321,7 @@ handle_connected (LightDMGreeter *greeter, guint8 *message, gsize message_length
g_string_append_printf (hint_string, " %s=%s", name, value);
}
+ priv->connected = TRUE;
g_debug ("Connected version=%s%s", version, hint_string->str);
g_free (version);
g_string_free (hint_string, TRUE);
@@ -301,6 +333,14 @@ handle_connected (LightDMGreeter *greeter, guint8 *message, gsize message_length
g_debug ("Setting autologin timer for %d seconds", timeout);
priv->autologin_timeout = g_timeout_add (timeout * 1000, timed_login_cb, greeter);
}
+
+ request = g_list_nth_data (priv->connect_requests, 0);
+ if (request)
+ {
+ request->complete = TRUE;
+ priv->connect_requests = g_list_remove (priv->connect_requests, request);
+ g_object_unref (request);
+ }
}
static void
@@ -408,6 +448,12 @@ handle_end_authentication (LightDMGreeter *greeter, guint8 *message, gsize messa
}
static void
+handle_idle (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
+{
+ g_signal_emit (G_OBJECT (greeter), signals[IDLE], 0);
+}
+
+static void
handle_reset (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
{
LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
@@ -432,6 +478,81 @@ handle_reset (LightDMGreeter *greeter, guint8 *message, gsize message_length, gs
g_signal_emit (G_OBJECT (greeter), signals[RESET], 0);
}
+static void
+handle_session_result (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
+{
+ LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
+ Request *request;
+
+ request = g_list_nth_data (priv->start_session_requests, 0);
+ if (request)
+ {
+ request->return_code = read_int (message, message_length, offset);
+ request->complete = TRUE;
+ priv->start_session_requests = g_list_remove (priv->start_session_requests, request);
+ g_object_unref (request);
+ }
+}
+
+static void
+handle_shared_dir_result (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
+{
+ LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
+ Request *request;
+
+ request = g_list_nth_data (priv->ensure_shared_data_dir_requests, 0);
+ if (request)
+ {
+ request->dir = read_string (message, message_length, offset);
+ /* Blank data dir means invalid user */
+ if (g_strcmp0 (request->dir, "") == 0)
+ {
+ g_free (request->dir);
+ request->dir = NULL;
+ }
+ request->complete = TRUE;
+ priv->ensure_shared_data_dir_requests = g_list_remove (priv->ensure_shared_data_dir_requests, request);
+ g_object_unref (request);
+ }
+}
+
+static void
+handle_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
+{
+ gsize offset = 0;
+ guint32 id;
+
+ id = read_int (message, message_length, &offset);
+ read_int (message, message_length, &offset);
+ switch (id)
+ {
+ case SERVER_MESSAGE_CONNECTED:
+ handle_connected (greeter, message, message_length, &offset);
+ break;
+ case SERVER_MESSAGE_PROMPT_AUTHENTICATION:
+ handle_prompt_authentication (greeter, message, message_length, &offset);
+ break;
+ case SERVER_MESSAGE_END_AUTHENTICATION:
+ handle_end_authentication (greeter, message, message_length, &offset);
+ break;
+ case SERVER_MESSAGE_SESSION_RESULT:
+ handle_session_result (greeter, message, message_length, &offset);
+ break;
+ case SERVER_MESSAGE_SHARED_DIR_RESULT:
+ handle_shared_dir_result (greeter, message, message_length, &offset);
+ break;
+ case SERVER_MESSAGE_IDLE:
+ handle_idle (greeter, message, message_length, &offset);
+ break;
+ case SERVER_MESSAGE_RESET:
+ handle_reset (greeter, message, message_length, &offset);
+ break;
+ default:
+ g_warning ("Unknown message from server: %d", id);
+ break;
+ }
+}
+
static guint8 *
read_message (LightDMGreeter *greeter, gsize *length, gboolean block)
{
@@ -493,39 +614,61 @@ from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
{
LightDMGreeter *greeter = data;
guint8 *message;
- gsize message_length, offset;
- guint32 id;
+ gsize message_length;
+ /* Read one message and process it */
message = read_message (greeter, &message_length, FALSE);
- if (!message)
- return TRUE;
-
- offset = 0;
- id = read_int (message, message_length, &offset);
- read_int (message, message_length, &offset);
- switch (id)
+ if (message)
{
- case SERVER_MESSAGE_PROMPT_AUTHENTICATION:
- handle_prompt_authentication (greeter, message, message_length, &offset);
- break;
- case SERVER_MESSAGE_END_AUTHENTICATION:
- handle_end_authentication (greeter, message, message_length, &offset);
- break;
- case SERVER_MESSAGE_IDLE:
- g_signal_emit (G_OBJECT (greeter), signals[IDLE], 0);
- break;
- case SERVER_MESSAGE_RESET:
- handle_reset (greeter, message, message_length, &offset);
- break;
- default:
- g_warning ("Unknown message from server: %d", id);
- break;
+ handle_message (greeter, message, message_length);
+ g_free (message);
}
- g_free (message);
return TRUE;
}
+static void
+send_connect (LightDMGreeter *greeter, gboolean resettable)
+{
+ guint8 message[MAX_MESSAGE_LENGTH];
+ gsize offset = 0;
+
+ g_debug ("Connecting to display manager...");
+ write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, string_length (VERSION) + int_length (), &offset);
+ write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset);
+ write_int (message, MAX_MESSAGE_LENGTH, resettable ? 1 : 0, &offset);
+ write_message (greeter, message, offset);
+}
+
+static void
+send_start_session (LightDMGreeter *greeter, const gchar *session)
+{
+ guint8 message[MAX_MESSAGE_LENGTH];
+ gsize offset = 0;
+
+ if (session)
+ g_debug ("Starting session %s", session);
+ else
+ g_debug ("Starting default session");
+
+ write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_START_SESSION, string_length (session), &offset);
+ write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
+ write_message (greeter, message, offset);
+}
+
+static void
+send_ensure_shared_data_dir (LightDMGreeter *greeter, const gchar *username)
+{
+ guint8 message[MAX_MESSAGE_LENGTH];
+ gsize offset = 0;
+
+ g_debug ("Ensuring data directory for user %s", username);
+
+ write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_ENSURE_SHARED_DIR, string_length (username), &offset);
+ write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
+ write_message (greeter, message, offset);
+}
+
/**
* lightdm_greeter_connect_sync:
* @greeter: The greeter to connect
@@ -540,10 +683,7 @@ lightdm_greeter_connect_sync (LightDMGreeter *greeter, GError **error)
{
LightDMGreeterPrivate *priv;
const gchar *fd;
- guint8 message[MAX_MESSAGE_LENGTH];
- guint8 *response;
- gsize response_length, offset = 0;
- guint32 id;
+ Request *request;
g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
@@ -568,31 +708,25 @@ lightdm_greeter_connect_sync (LightDMGreeter *greeter, GError **error)
g_io_channel_set_encoding (priv->from_server_channel, NULL, NULL);
g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
- g_debug ("Connecting to display manager...");
- write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, string_length (VERSION) + int_length (), &offset);
- write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset);
- write_int (message, MAX_MESSAGE_LENGTH, priv->resettable ? 1 : 0, &offset);
- write_message (greeter, message, offset);
-
- response = read_message (greeter, &response_length, TRUE);
- if (!response)
- return FALSE;
-
- offset = 0;
- id = read_int (response, response_length, &offset);
- read_int (response, response_length, &offset);
- if (id == SERVER_MESSAGE_CONNECTED)
- handle_connected (greeter, response, response_length, &offset);
- g_free (response);
- if (id != SERVER_MESSAGE_CONNECTED)
+ /* Read until we are connected */
+ send_connect (greeter, priv->resettable);
+ request = request_new ();
+ priv->connect_requests = g_list_append (priv->connect_requests, g_object_ref (request));
+ do
{
- g_warning ("Expected CONNECTED message, got %d", id);
- return FALSE;
- }
+ guint8 *message;
+ gsize message_length;
- priv->connected = TRUE;
+ message = read_message (greeter, &message_length, TRUE);
+ if (!message)
+ break;
+ handle_message (greeter, message, message_length);
+ g_free (message);
+ } while (!request->complete);
- return TRUE;
+ g_object_unref (request);
+
+ return request->complete;
}
/**
@@ -1128,10 +1262,8 @@ gboolean
lightdm_greeter_start_session_sync (LightDMGreeter *greeter, const gchar *session, GError **error)
{
LightDMGreeterPrivate *priv;
- guint8 message[MAX_MESSAGE_LENGTH];
- guint8 *response;
- gsize response_length, offset = 0;
- guint32 id, return_code = 1;
+ Request *request;
+ guint32 return_code;
g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
@@ -1140,28 +1272,24 @@ lightdm_greeter_start_session_sync (LightDMGreeter *greeter, const gchar *sessio
g_return_val_if_fail (priv->connected, FALSE);
g_return_val_if_fail (priv->is_authenticated, FALSE);
- if (session)
- g_debug ("Starting session %s", session);
- else
- g_debug ("Starting default session");
-
- write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_START_SESSION, string_length (session), &offset);
- write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
- write_message (greeter, message, offset);
-
- response = read_message (greeter, &response_length, TRUE);
- if (!response)
- return FALSE;
+ /* Read until the session is started */
+ send_start_session (greeter, session);
+ request = request_new ();
+ priv->start_session_requests = g_list_append (priv->start_session_requests, g_object_ref (request));
+ do
+ {
+ guint8 *message;
+ gsize message_length;
- offset = 0;
- id = read_int (response, response_length, &offset);
- read_int (response, response_length, &offset);
- if (id == SERVER_MESSAGE_SESSION_RESULT)
- return_code = read_int (response, response_length, &offset);
- else
- g_warning ("Expected SESSION_RESULT message, got %d", id);
+ message = read_message (greeter, &message_length, TRUE);
+ if (!message)
+ break;
+ handle_message (greeter, message, message_length);
+ g_free (message);
+ } while (!request->complete);
- g_free (response);
+ return_code = request->return_code;
+ g_object_unref (request);
return return_code == 0;
}
@@ -1188,11 +1316,8 @@ gchar *
lightdm_greeter_ensure_shared_data_dir_sync (LightDMGreeter *greeter, const gchar *username)
{
LightDMGreeterPrivate *priv;
- guint8 message[MAX_MESSAGE_LENGTH];
- guint8 *response;
- gsize response_length, offset = 0;
- guint32 id;
- gchar *data_dir = NULL;
+ Request *request;
+ gchar *data_dir;
g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
@@ -1200,32 +1325,24 @@ lightdm_greeter_ensure_shared_data_dir_sync (LightDMGreeter *greeter, const gcha
g_return_val_if_fail (priv->connected, NULL);
- g_debug ("Ensuring data directory for user %s", username);
-
- write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_ENSURE_SHARED_DIR, string_length (username), &offset);
- write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
- write_message (greeter, message, offset);
-
- response = read_message (greeter, &response_length, TRUE);
- if (!response)
- return NULL;
-
- offset = 0;
- id = read_int (response, response_length, &offset);
- read_int (response, response_length, &offset);
- if (id == SERVER_MESSAGE_SHARED_DIR_RESULT)
- data_dir = read_string (response, response_length, &offset);
- else
- g_warning ("Expected SHARED_DIR_RESULT message, got %d", id);
-
- /* Blank data dir means invalid user */
- if (g_strcmp0 (data_dir, "") == 0)
+ /* Read until a response */
+ send_ensure_shared_data_dir (greeter, username);
+ request = request_new ();
+ priv->ensure_shared_data_dir_requests = g_list_append (priv->ensure_shared_data_dir_requests, g_object_ref (request));
+ do
{
- g_free (data_dir);
- data_dir = NULL;
- }
+ guint8 *message;
+ gsize message_length;
- g_free (response);
+ message = read_message (greeter, &message_length, TRUE);
+ if (!message)
+ break;
+ handle_message (greeter, message, message_length);
+ g_free (message);
+ } while (!request->complete);
+
+ data_dir = g_strdup (request->dir);
+ g_object_unref (request);
return data_dir;
}
@@ -1557,3 +1674,25 @@ lightdm_greeter_class_init (LightDMGreeterClass *klass)
NULL,
G_TYPE_NONE, 0);
}
+
+static void
+request_init (Request *request)
+{
+}
+
+static void
+request_finalize (GObject *object)
+{
+ Request *request = REQUEST (object);
+
+ g_free (request->dir);
+
+ G_OBJECT_CLASS (request_parent_class)->finalize (object);
+}
+
+static void
+request_class_init (RequestClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = request_finalize;
+}