]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - src/vnc-server.c
Load all users only when really needed
[sojka/lightdm.git] / src / vnc-server.c
1 /*
2  * Copyright (C) 2010-2011 Robert Ancell.
3  * Author: Robert Ancell <robert.ancell@canonical.com>
4  *
5  * This program is free software: you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License as published by the Free Software
7  * Foundation, either version 3 of the License, or (at your option) any later
8  * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
9  * license.
10  */
11
12 #include <gio/gio.h>
13
14 #include "vnc-server.h"
15
16 enum {
17     NEW_CONNECTION,
18     LAST_SIGNAL
19 };
20 static guint signals[LAST_SIGNAL] = { 0 };
21
22 struct VNCServerPrivate
23 {
24     /* Port to listen on */
25     guint port;
26
27     /* Address to listen on */
28     gchar *listen_address;
29
30     /* Listening sockets */
31     GSocket *socket, *socket6;
32 };
33
34 G_DEFINE_TYPE (VNCServer, vnc_server, G_TYPE_OBJECT);
35
36 VNCServer *
37 vnc_server_new (void)
38 {
39     return g_object_new (VNC_SERVER_TYPE, NULL);
40 }
41
42 void
43 vnc_server_set_port (VNCServer *server, guint port)
44 {
45     g_return_if_fail (server != NULL);
46     server->priv->port = port;
47 }
48
49 guint
50 vnc_server_get_port (VNCServer *server)
51 {
52     g_return_val_if_fail (server != NULL, 0);
53     return server->priv->port;
54 }
55
56 void
57 vnc_server_set_listen_address (VNCServer *server, const gchar *listen_address)
58 {
59     g_return_if_fail (server != NULL);
60
61     g_free (server->priv->listen_address);
62     server->priv->listen_address = g_strdup (listen_address);
63 }
64
65 const gchar *
66 vnc_server_get_listen_address (VNCServer *server)
67 {
68     g_return_val_if_fail (server != NULL, NULL);
69     return server->priv->listen_address;
70 }
71
72 static gboolean
73 read_cb (GSocket *socket, GIOCondition condition, VNCServer *server)
74 {
75     GError *error = NULL;
76     GSocket *client_socket;
77
78     client_socket = g_socket_accept (socket, NULL, &error);
79     if (error)
80         g_warning ("Failed to get connection from from VNC socket: %s", error->message);
81     g_clear_error (&error);
82
83     if (client_socket)
84     {
85         GInetSocketAddress *address;
86         gchar *hostname;
87
88         address = G_INET_SOCKET_ADDRESS (g_socket_get_remote_address (client_socket, NULL));
89         hostname = g_inet_address_to_string (g_inet_socket_address_get_address (address));
90         g_debug ("Got VNC connection from %s:%d", hostname, g_inet_socket_address_get_port (address));
91         g_free (hostname);
92
93         g_signal_emit (server, signals[NEW_CONNECTION], 0, client_socket);
94     }
95
96     return TRUE;
97 }
98
99 static GSocket *
100 open_tcp_socket (GSocketFamily family, guint port, const gchar *listen_address, GError **error)
101 {
102     GSocket *socket;
103     GSocketAddress *address;
104
105     socket = g_socket_new (family, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, error);
106     if (!socket)
107         return NULL;
108
109     if (listen_address) 
110     {
111         GList *addresses;
112
113         addresses = g_resolver_lookup_by_name (g_resolver_get_default (), listen_address, NULL, error);
114         if (!addresses)
115         {
116             g_object_unref (socket);
117             return NULL;
118         }
119         address = g_inet_socket_address_new (addresses->data, port);
120         g_resolver_free_addresses (addresses);
121     }
122     else
123         address = g_inet_socket_address_new (g_inet_address_new_any (family), port);
124     if (!g_socket_bind (socket, address, TRUE, error) ||
125         !g_socket_listen (socket, error))
126     {
127         g_object_unref (socket);
128         return NULL;
129     }
130
131     return socket;
132 }
133
134 gboolean
135 vnc_server_start (VNCServer *server)
136 {
137     GSource *source;
138     GError *error = NULL;
139
140     g_return_val_if_fail (server != NULL, FALSE);
141
142     server->priv->socket = open_tcp_socket (G_SOCKET_FAMILY_IPV4, server->priv->port, server->priv->listen_address, &error);
143     if (error)
144         g_warning ("Failed to create IPv4 VNC socket: %s", error->message);
145     g_clear_error (&error);
146
147     if (server->priv->socket)
148     {
149         source = g_socket_create_source (server->priv->socket, G_IO_IN, NULL);
150         g_source_set_callback (source, (GSourceFunc) read_cb, server, NULL);
151         g_source_attach (source, NULL);
152     }
153
154     server->priv->socket6 = open_tcp_socket (G_SOCKET_FAMILY_IPV6, server->priv->port, server->priv->listen_address, &error);
155     if (error)
156         g_warning ("Failed to create IPv6 VNC socket: %s", error->message);
157     g_clear_error (&error);
158
159     if (server->priv->socket6)
160     {
161         source = g_socket_create_source (server->priv->socket6, G_IO_IN, NULL);
162         g_source_set_callback (source, (GSourceFunc) read_cb, server, NULL);
163         g_source_attach (source, NULL);
164     }
165
166     if (!server->priv->socket && !server->priv->socket6)
167         return FALSE;
168
169     return TRUE;
170 }
171
172 static void
173 vnc_server_init (VNCServer *server)
174 {
175     server->priv = G_TYPE_INSTANCE_GET_PRIVATE (server, VNC_SERVER_TYPE, VNCServerPrivate);
176     server->priv->port = 5900;
177 }
178
179 static void
180 vnc_server_finalize (GObject *object)
181 {
182     VNCServer *self = VNC_SERVER (object);
183
184     g_free (self->priv->listen_address);
185     g_clear_object (&self->priv->socket);
186     g_clear_object (&self->priv->socket6);
187
188     G_OBJECT_CLASS (vnc_server_parent_class)->finalize (object);
189 }
190
191 static void
192 vnc_server_class_init (VNCServerClass *klass)
193 {
194     GObjectClass *object_class = G_OBJECT_CLASS (klass);
195
196     object_class->finalize = vnc_server_finalize;
197
198     g_type_class_add_private (klass, sizeof (VNCServerPrivate));
199
200     signals[NEW_CONNECTION] =
201         g_signal_new (VNC_SERVER_SIGNAL_NEW_CONNECTION,
202                       G_TYPE_FROM_CLASS (klass),
203                       G_SIGNAL_RUN_LAST,
204                       G_STRUCT_OFFSET (VNCServerClass, new_connection),
205                       NULL, NULL,
206                       NULL,
207                       G_TYPE_NONE, 1, G_TYPE_SOCKET);
208 }