]> rtime.felk.cvut.cz Git - sojka/lightdm.git/commitdiff
Make reading from the server non-blocking, add get_in_authentication() method
authorRobert Ancell <robert.ancell@canonical.com>
Wed, 13 Apr 2011 07:06:12 +0000 (17:06 +1000)
committerRobert Ancell <robert.ancell@canonical.com>
Wed, 13 Apr 2011 07:06:12 +0000 (17:06 +1000)
liblightdm-gobject/Makefile.am
liblightdm-gobject/greeter-protocol.h [new file with mode: 0644]
liblightdm-gobject/greeter.c
liblightdm-gobject/greeter.h

index d972b328d84939a59f3af08da7499ae77d19aa67..4b3b2f3d8e9f6583e5735ac225ee29bc0ed5d174 100644 (file)
@@ -13,11 +13,11 @@ liblightdm_gobject_0includedir=$(includedir)/lightdm-gobject-0/lightdm
 liblightdm_gobject_0_la_LIBADD = $(LIBLIGHTDM_GOBJECT_LIBS)
 liblightdm_gobject_0_la_CFLAGS = $(LIBLIGHTDM_GOBJECT_CFLAGS) \
        $(WARN_CFLAGS) \
-       -I../src \
        -DXSESSIONS_DIR=\"$(XSESSIONS_DIR)\"
 
 liblightdm_gobject_0_la_SOURCES= \
        greeter.c \
+       greeter-protocol.h \
        language.c \
        layout.c \
        session.c \
diff --git a/liblightdm-gobject/greeter-protocol.h b/liblightdm-gobject/greeter-protocol.h
new file mode 100644 (file)
index 0000000..5c820b7
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2010 Robert Ancell.
+ * Author: Robert Ancell <robert.ancell@canonical.com>
+ * 
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
+ * license.
+ */
+
+#ifndef _GREETER_PROTOCOL_H_
+#define _GREETER_PROTOCOL_H_
+
+typedef enum
+{
+    /* Messages from the greeter to the server */
+    GREETER_MESSAGE_CONNECT                 = 1,
+    GREETER_MESSAGE_START_AUTHENTICATION    = 2,
+    GREETER_MESSAGE_CONTINUE_AUTHENTICATION = 3,
+    GREETER_MESSAGE_LOGIN                   = 4,
+
+    /* Messages from the server to the greeter */
+    GREETER_MESSAGE_CONNECTED               = 101,
+    GREETER_MESSAGE_QUIT                    = 102,
+    GREETER_MESSAGE_PROMPT_AUTHENTICATION   = 103,
+    GREETER_MESSAGE_END_AUTHENTICATION      = 104
+} GreeterMessage;
+
+#endif /* _GREETER_PROTOCOL_H_ */
index 98cbea8b916d0714fd13aa82d2ce44eb18b11d64..bb32661cdc8f34ea92918cf26f6d2b4d57c3320f 100644 (file)
@@ -34,6 +34,7 @@ enum {
     PROP_TIMED_LOGIN_USER,
     PROP_TIMED_LOGIN_DELAY,
     PROP_AUTHENTICATION_USER,
+    PROP_IN_AUTHENTICATION,
     PROP_IS_AUTHENTICATED,
     PROP_CAN_SUSPEND,
     PROP_CAN_HIBERNATE,
@@ -62,6 +63,8 @@ struct _LdmGreeterPrivate
     GDBusProxy *session_proxy, *user_proxy;
 
     GIOChannel *to_server_channel, *from_server_channel;
+    gchar *read_buffer;
+    gsize n_read;
 
     Display *display;
 
@@ -88,6 +91,7 @@ struct _LdmGreeterPrivate
     gchar *default_session;
 
     gchar *authentication_user;
+    gboolean in_authentication;
     gboolean is_authenticated;
 
     gchar *timed_user;
@@ -97,6 +101,8 @@ struct _LdmGreeterPrivate
 
 G_DEFINE_TYPE (LdmGreeter, ldm_greeter, G_TYPE_OBJECT);
 
+#define HEADER_SIZE 8
+
 /**
  * ldm_greeter_new:
  *
@@ -122,34 +128,23 @@ timed_login_cb (gpointer data)
 }
 
 static guint32
-read_int (LdmGreeter *greeter)
+int_length ()
 {
-    guint32 value;
-    g_io_channel_read_chars (greeter->priv->from_server_channel, (gchar *) &value, sizeof (value), NULL, NULL);
-    return value;
+    return 4;
 }
 
 static void
 write_int (LdmGreeter *greeter, guint32 value)
 {
-    if (g_io_channel_write_chars (greeter->priv->to_server_channel, (const gchar *) &value, sizeof (value), NULL, NULL) != G_IO_STATUS_NORMAL)
+    gchar buffer[4];
+    buffer[0] = value >> 24;
+    buffer[1] = (value >> 16) & 0xFF;
+    buffer[2] = (value >> 8) & 0xFF;
+    buffer[3] = value & 0xFF;
+    if (g_io_channel_write_chars (greeter->priv->to_server_channel, buffer, int_length (), NULL, NULL) != G_IO_STATUS_NORMAL)
         g_warning ("Error writing to server");
 }
 
-static gchar *
-read_string (LdmGreeter *greeter)
-{
-    guint32 length;
-    gchar *value;
-
-    length = read_int (greeter);
-    value = g_malloc (sizeof (gchar *) * (length + 1));
-    g_io_channel_read_chars (greeter->priv->from_server_channel, value, length, NULL, NULL);
-    value[length] = '\0';
-
-    return value;
-}
-
 static void
 write_string (LdmGreeter *greeter, const gchar *value)
 {
@@ -158,9 +153,40 @@ write_string (LdmGreeter *greeter, const gchar *value)
 }
 
 static guint32
-int_length ()
+read_int (LdmGreeter *greeter, gsize *offset)
 {
-    return sizeof (guint32);
+    guint32 value;
+    gchar *buffer;
+    if (greeter->priv->n_read - *offset < int_length ())
+    {
+        g_warning ("Not enough space for int, need %i, got %zi", int_length (), greeter->priv->n_read - *offset);
+        return 0;
+    }
+    buffer = greeter->priv->read_buffer + *offset;
+    value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
+    *offset += int_length ();
+    return value;
+}
+
+static gchar *
+read_string (LdmGreeter *greeter, gsize *offset)
+{
+    guint32 length;
+    gchar *value;
+
+    length = read_int (greeter, offset);
+    if (greeter->priv->n_read - *offset < length)
+    {
+        g_warning ("Not enough space for string, need %u, got %zu", length, greeter->priv->n_read - *offset);
+        return g_strdup ("");
+    }
+
+    value = g_malloc (sizeof (gchar) * (length + 1));
+    memcpy (value, greeter->priv->read_buffer + *offset, length);
+    value[length] = '\0';
+    *offset += length;
+
+    return value;
 }
 
 static guint32
@@ -176,6 +202,12 @@ write_header (LdmGreeter *greeter, guint32 id, guint32 length)
     write_int (greeter, length);
 }
 
+static guint32 get_packet_length (LdmGreeter *greeter)
+{
+    gsize offset = 4;
+    return read_int (greeter, &offset);
+}
+
 static void
 flush (LdmGreeter *greeter)
 {
@@ -183,11 +215,11 @@ flush (LdmGreeter *greeter)
 }
 
 static void
-handle_prompt_authentication (LdmGreeter *greeter)
+handle_prompt_authentication (LdmGreeter *greeter, gsize *offset)
 {
     int n_messages, i;
 
-    n_messages = read_int (greeter);
+    n_messages = read_int (greeter, offset);
     g_debug ("Prompt user with %d message(s)", n_messages);
 
     for (i = 0; i < n_messages; i++)
@@ -195,8 +227,8 @@ handle_prompt_authentication (LdmGreeter *greeter)
         int msg_style;
         gchar *msg;
 
-        msg_style = read_int (greeter);
-        msg = read_string (greeter);
+        msg_style = read_int (greeter, offset);
+        msg = read_string (greeter, offset);
 
         // FIXME: Should stop on prompts?
         switch (msg_style)
@@ -221,18 +253,52 @@ static gboolean
 from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
 {
     LdmGreeter *greeter = data;
-    int message, return_code;
+    gsize n_to_read, n_read, offset;
+    GIOStatus status;
+    guint32 id, return_code;
+    GError *error = NULL;
+
+    n_to_read = HEADER_SIZE;
+    if (greeter->priv->n_read >= HEADER_SIZE)
+        n_to_read += get_packet_length (greeter);
+
+    status = g_io_channel_read_chars (greeter->priv->from_server_channel,
+                                      greeter->priv->read_buffer + greeter->priv->n_read,
+                                      n_to_read - greeter->priv->n_read,
+                                      &n_read,
+                                      &error);
+    if (status != G_IO_STATUS_NORMAL)
+        g_warning ("Error reading from server: %s", error->message);
+    g_clear_error (&error);
+    if (status != G_IO_STATUS_NORMAL)
+        return TRUE;
 
-    message = read_int (greeter);
-    read_int (greeter); // length
-    switch (message)
+    greeter->priv->n_read += n_read;
+    if (greeter->priv->n_read != n_to_read)
+        return TRUE;
+
+    /* If have header, rerun for content */
+    if (greeter->priv->n_read == HEADER_SIZE)
+    {
+        n_to_read = get_packet_length (greeter);
+        if (n_to_read > 0)
+        {
+            greeter->priv->read_buffer = g_realloc (greeter->priv->read_buffer, HEADER_SIZE + n_to_read);
+            return from_server_cb (source, condition, data);
+        }
+    }
+
+    offset = 0;
+    id = read_int (greeter, &offset);
+    read_int (greeter, &offset);
+    switch (id)
     {
     case GREETER_MESSAGE_CONNECTED:
-        greeter->priv->theme = read_string (greeter);
-        greeter->priv->default_layout = read_string (greeter);
-        greeter->priv->default_session = read_string (greeter);
-        greeter->priv->timed_user = read_string (greeter);
-        greeter->priv->login_delay = read_int (greeter);
+        greeter->priv->theme = read_string (greeter, &offset);
+        greeter->priv->default_layout = read_string (greeter, &offset);
+        greeter->priv->default_session = read_string (greeter, &offset);
+        greeter->priv->timed_user = read_string (greeter, &offset);
+        greeter->priv->login_delay = read_int (greeter, &offset);
 
         g_debug ("Connected theme=%s default-layout=%s default-session=%s timed-user=%s login-delay=%d",
                  greeter->priv->theme,
@@ -248,13 +314,14 @@ from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
         g_signal_emit (G_OBJECT (greeter), signals[CONNECTED], 0);
         break;
     case GREETER_MESSAGE_QUIT:
+        g_debug ("Got quit request from server");
         g_signal_emit (G_OBJECT (greeter), signals[QUIT], 0);
         break;
     case GREETER_MESSAGE_PROMPT_AUTHENTICATION:
-        handle_prompt_authentication (greeter);
+        handle_prompt_authentication (greeter, &offset);
         break;
     case GREETER_MESSAGE_END_AUTHENTICATION:
-        return_code = read_int (greeter);
+        return_code = read_int (greeter, &offset);
         g_debug ("Authentication complete with return code %d", return_code);
         greeter->priv->is_authenticated = (return_code == 0);
         if (!greeter->priv->is_authenticated)
@@ -265,10 +332,12 @@ from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
         g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0);
         break;
     default:
-        g_warning ("Unknown message from server: %d", message);
+        g_warning ("Unknown message from server: %d", id);
         break;
     }
 
+    greeter->priv->n_read = 0;
+
     return TRUE;
 }
 
@@ -948,6 +1017,21 @@ ldm_greeter_cancel_authentication (LdmGreeter *greeter)
     g_return_if_fail (LDM_IS_GREETER (greeter));
 }
 
+/**
+ * ldm_greeter_get_in_authentication:
+ * @greeter: A #LdmGreeter
+ *
+ * Checks if the greeter is in the process of authenticating.
+ *
+ * Return value: TRUE if the greeter is authenticating a user.
+ **/
+gboolean
+ldm_greeter_get_in_authentication (LdmGreeter *greeter)
+{
+    g_return_val_if_fail (greeter != NULL, FALSE);
+    return greeter->priv->in_authentication;
+}
+
 /**
  * ldm_greeter_get_is_authenticated:
  * @greeter: A #LdmGreeter
@@ -1225,6 +1309,7 @@ static void
 ldm_greeter_init (LdmGreeter *greeter)
 {
     greeter->priv = G_TYPE_INSTANCE_GET_PRIVATE (greeter, LDM_TYPE_GREETER, LdmGreeterPrivate);
+    greeter->priv->read_buffer = g_malloc (HEADER_SIZE);
 
     g_debug ("default-language=%s", ldm_greeter_get_default_language (greeter));
 }
@@ -1290,6 +1375,9 @@ ldm_greeter_get_property (GObject    *object,
     case PROP_AUTHENTICATION_USER:
         g_value_set_string (value, ldm_greeter_get_authentication_user (self));
         break;
+    case PROP_IN_AUTHENTICATION:
+        g_value_set_boolean (value, ldm_greeter_get_in_authentication (self));
+        break;
     case PROP_IS_AUTHENTICATED:
         g_value_set_boolean (value, ldm_greeter_get_is_authenticated (self));
         break;
@@ -1392,6 +1480,13 @@ ldm_greeter_class_init (LdmGreeterClass *klass)
                                                           "The user being authenticated",
                                                           NULL,
                                                           G_PARAM_READABLE));
+    g_object_class_install_property (object_class,
+                                     PROP_IN_AUTHENTICATION,
+                                     g_param_spec_boolean ("in-authentication",
+                                                           "in-authentication",
+                                                           "TRUE if a user is being authenticated",
+                                                           FALSE,
+                                                           G_PARAM_READABLE));
     g_object_class_install_property (object_class,
                                      PROP_IS_AUTHENTICATED,
                                      g_param_spec_boolean ("is-authenticated",
index 47de068e0cd0eb41e252757550ff128412e9526a..e5ff9e4f7590f3ea4b8e96d15da33cd7e78c9262 100644 (file)
@@ -99,6 +99,8 @@ void ldm_greeter_provide_secret (LdmGreeter *greeter, const gchar *secret);
 
 void ldm_greeter_cancel_authentication (LdmGreeter *greeter);
 
+gboolean ldm_greeter_get_in_authentication (LdmGreeter *greeter);
+
 gboolean ldm_greeter_get_is_authenticated (LdmGreeter *greeter);
 
 const gchar *ldm_greeter_get_authentication_user (LdmGreeter *greeter);