]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - src/greeter-socket.c
Releasing 1.20.0
[sojka/lightdm.git] / src / greeter-socket.c
1 /*
2  * Copyright (C) 2010-2016 Canonical Ltd.
3  *
4  * This program is free software: you can redistribute it and/or modify it under
5  * the terms of the GNU General Public License as published by the Free Software
6  * Foundation, either version 3 of the License, or (at your option) any later
7  * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
8  * license.
9  */
10
11 #include <config.h>
12
13 #include <errno.h>
14 #include <sys/stat.h>
15 #include <gio/gio.h>
16 #include <gio/gunixsocketaddress.h>
17
18 #include "greeter-socket.h"
19
20 enum {
21     CREATE_GREETER,
22     LAST_SIGNAL
23 };
24 static guint signals[LAST_SIGNAL] = { 0 };
25
26 struct GreeterSocketPrivate
27 {
28     /* Path of socket to use */
29     gchar *path;
30
31     /* Listening UNIX socket */
32     GSocket *socket;
33
34     /* Source for listening for connections */
35     GSource *source;
36
37     /* Socket to greeter */
38     GSocket *greeter_socket;
39
40     /* Greeter connected on this socket */
41     Greeter *greeter;
42 };
43
44 G_DEFINE_TYPE (GreeterSocket, greeter_socket, G_TYPE_OBJECT);
45
46 GreeterSocket *
47 greeter_socket_new (const gchar *path)
48 {
49     GreeterSocket *socket;
50
51     socket = g_object_new (GREETER_SOCKET_TYPE, NULL);
52     socket->priv->path = g_strdup (path);
53
54     return socket;
55 }
56
57 static void
58 greeter_disconnected_cb (Greeter *greeter, GreeterSocket *socket)
59 {
60     if (greeter == socket->priv->greeter)
61     {
62         g_clear_object (&socket->priv->greeter);
63         g_clear_object (&socket->priv->greeter_socket);
64     }
65 }
66
67 static gboolean
68 greeter_connect_cb (GSocket *s, GIOCondition condition, GreeterSocket *socket)
69 {
70     GSocket *new_socket;
71     GError *error = NULL;
72
73     new_socket = g_socket_accept (socket->priv->socket, NULL, &error);
74     if (error)
75         g_warning ("Failed to accept greeter connection: %s", error->message);
76     g_clear_error (&error);
77     if (!new_socket)
78         return G_SOURCE_CONTINUE;
79
80     /* Greeter already connected */
81     if (socket->priv->greeter)
82     {
83         g_socket_close (new_socket, NULL);
84         g_object_unref (new_socket);
85         return G_SOURCE_CONTINUE;
86     }
87
88     socket->priv->greeter_socket = new_socket;
89     g_signal_emit (socket, signals[CREATE_GREETER], 0, &socket->priv->greeter);
90     g_signal_connect (socket->priv->greeter, GREETER_SIGNAL_DISCONNECTED, G_CALLBACK (greeter_disconnected_cb), socket);
91     greeter_set_file_descriptors (socket->priv->greeter, g_socket_get_fd (new_socket), g_socket_get_fd (new_socket));
92
93     return G_SOURCE_CONTINUE;
94 }
95
96 gboolean
97 greeter_socket_start (GreeterSocket *socket, GError **error)
98 {
99     GSocketAddress *address;
100     gboolean result;
101
102     g_return_val_if_fail (socket != NULL, FALSE);
103     g_return_val_if_fail (socket->priv->socket == NULL, FALSE);  
104
105     socket->priv->socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, error);
106     if (!socket->priv->socket)
107         return FALSE;
108
109     unlink (socket->priv->path);  
110     address = g_unix_socket_address_new (socket->priv->path);
111     result = g_socket_bind (socket->priv->socket, address, FALSE, error);
112     g_object_unref (address);
113     if (!result)
114         return FALSE;
115     if (!g_socket_listen (socket->priv->socket, error))
116         return FALSE;
117
118     socket->priv->source = g_socket_create_source (socket->priv->socket, G_IO_IN, NULL);
119     g_source_set_callback (socket->priv->source, (GSourceFunc) greeter_connect_cb, socket, NULL);
120     g_source_attach (socket->priv->source, NULL);
121
122     /* Allow to be written to */
123     if (chmod (socket->priv->path, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
124     {
125         g_set_error (error,
126                      G_FILE_ERROR,
127                      g_file_error_from_errno (errno),
128                      "Failed to set permissions on greeter socket %s: %s",
129                      socket->priv->path,
130                      g_strerror (errno));     
131         return FALSE;
132     }
133
134     return TRUE;
135 }
136
137 static void
138 greeter_socket_init (GreeterSocket *socket)
139 {
140     socket->priv = G_TYPE_INSTANCE_GET_PRIVATE (socket, GREETER_SOCKET_TYPE, GreeterSocketPrivate);
141 }
142
143 static void
144 greeter_socket_finalize (GObject *object)
145 {
146     GreeterSocket *self = GREETER_SOCKET (object);
147
148     if (self->priv->path)
149         unlink (self->priv->path); 
150     g_free (self->priv->path);
151     g_clear_object (&self->priv->socket);
152     g_clear_object (&self->priv->source);
153     g_clear_object (&self->priv->greeter_socket);
154     g_clear_object (&self->priv->greeter);
155
156     G_OBJECT_CLASS (greeter_socket_parent_class)->finalize (object);
157 }
158
159 static void
160 greeter_socket_class_init (GreeterSocketClass *klass)
161 {
162     GObjectClass *object_class = G_OBJECT_CLASS (klass);
163
164     object_class->finalize = greeter_socket_finalize;
165
166     signals[CREATE_GREETER] =
167         g_signal_new (GREETER_SOCKET_SIGNAL_CREATE_GREETER,
168                       G_TYPE_FROM_CLASS (klass),
169                       G_SIGNAL_RUN_LAST,
170                       G_STRUCT_OFFSET (GreeterSocketClass, create_greeter),
171                       g_signal_accumulator_first_wins,
172                       NULL,
173                       NULL,
174                       GREETER_TYPE, 0);
175
176     g_type_class_add_private (klass, sizeof (GreeterSocketPrivate));
177 }