From: Robert Ancell Date: Mon, 28 Apr 2014 22:46:22 +0000 (+1200) Subject: Handle unexpected messages during synchronous calls. This is taken from an unfinished... X-Git-Url: https://rtime.felk.cvut.cz/gitweb/sojka/lightdm.git/commitdiff_plain/084ef0cfec4ecef001a0f66666a3488f53ed9fd8 Handle unexpected messages during synchronous calls. This is taken from an unfinished asynchronous call branch. --- 084ef0cfec4ecef001a0f66666a3488f53ed9fd8 diff --cc liblightdm-gobject/greeter.c index 385ffaa8,8ce0cffc..fe67fc4a --- a/liblightdm-gobject/greeter.c +++ b/liblightdm-gobject/greeter.c @@@ -96,10 -97,24 +100,26 @@@ typedef enu SERVER_MESSAGE_END_AUTHENTICATION, SERVER_MESSAGE_SESSION_RESULT, SERVER_MESSAGE_SHARED_DIR_RESULT, + SERVER_MESSAGE_IDLE, + 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: * @@@ -113,27 -128,16 +133,37 @@@ lightdm_greeter_new ( return g_object_new (LIGHTDM_TYPE_GREETER, NULL); } +/** + * lightdm_greeter_set_resettable: + * @greeter: A #LightDMGreeter + * @resettable: Whether the greeter wants to be reset instead of killed after the user logs in + * + * Set whether the greeter will be reset instead of killed after the user logs in. + * This must be called before lightdm_greeter_connect is called. + **/ +void +lightdm_greeter_set_resettable (LightDMGreeter *greeter, gboolean resettable) +{ + LightDMGreeterPrivate *priv; + + g_return_if_fail (LIGHTDM_IS_GREETER (greeter)); + + priv = GET_PRIVATE (greeter); + + g_return_if_fail (!priv->connected); + 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) { @@@ -407,31 -421,75 +447,112 @@@ handle_end_authentication (LightDMGreet g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0); } ++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); + GString *hint_string; + + g_hash_table_remove_all (priv->hints); + + hint_string = g_string_new (""); + while (*offset < message_length) + { + gchar *name, *value; + + name = read_string (message, message_length, offset); + value = read_string (message, message_length, offset); + g_hash_table_insert (priv->hints, name, value); + g_string_append_printf (hint_string, " %s=%s", name, value); + } + + g_debug ("Reset%s", hint_string->str); + g_string_free (hint_string, TRUE); + + 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) { @@@ -526,6 -564,47 +627,48 @@@ from_server_cb (GIOChannel *source, GIO return TRUE; } + static void -send_connect (LightDMGreeter *greeter) ++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), &offset); ++ 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 @@@ -568,31 -644,25 +708,25 @@@ lightdm_greeter_connect_sync (LightDMGr 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); ++ 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; } /** @@@ -1518,42 -1571,26 +1635,64 @@@ lightdm_greeter_class_init (LightDMGree NULL, NULL, NULL, G_TYPE_NONE, 0); + + /** + * LightDMGreeter::idle: + * @greeter: A #LightDMGreeter + * + * The ::idle signal gets emitted when the user has logged in and the + * greeter is no longer needed. + * + * This signal only matters if the greeter has marked itself as + * resettable using lightdm_greeter_set_resettable(). + **/ + signals[IDLE] = + g_signal_new ("idle", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (LightDMGreeterClass, idle), + NULL, NULL, + NULL, + G_TYPE_NONE, 0); + + /** + * LightDMGreeter::reset: + * @greeter: A #LightDMGreeter + * + * The ::reset signal gets emitted when the user is returning to a greeter + * that was previously marked idle. + * + * This signal only matters if the greeter has marked itself as + * resettable using lightdm_greeter_set_resettable(). + **/ + signals[RESET] = + g_signal_new ("reset", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (LightDMGreeterClass, reset), + NULL, NULL, + 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; + }