]> rtime.felk.cvut.cz Git - sojka/lightdm.git/commitdiff
Handle unexpected messages during synchronous calls. This is taken from an unfinished...
authorRobert Ancell <robert.ancell@canonical.com>
Mon, 28 Apr 2014 22:46:22 +0000 (10:46 +1200)
committerRobert Ancell <robert.ancell@canonical.com>
Mon, 28 Apr 2014 22:46:22 +0000 (10:46 +1200)
1  2 
liblightdm-gobject/greeter.c

index 385ffaa80a192f9c003e5fcc0d70a60f35c699a6,8ce0cffcb10db9ed55c520171272ae3576c65fac..fe67fc4a19e04bf383fa56cd7f41d7420395820f
@@@ -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;
  }
  
 -send_connect (LightDMGreeter *greeter)
+ static void
 -    write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, string_length (VERSION), &offset);
++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
@@@ -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;
+ }