]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - src/vnc-server.c
Refactored code to replace hardcoded signal identification strings by constants.
[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     /* Listening sockets */
28     GSocket *socket, *socket6;
29 };
30
31 G_DEFINE_TYPE (VNCServer, vnc_server, G_TYPE_OBJECT);
32
33 VNCServer *
34 vnc_server_new (void)
35 {
36     return g_object_new (VNC_SERVER_TYPE, NULL);
37 }
38
39 void
40 vnc_server_set_port (VNCServer *server, guint port)
41 {
42     g_return_if_fail (server != NULL);
43     server->priv->port = port;
44 }
45
46 guint
47 vnc_server_get_port (VNCServer *server)
48 {
49     g_return_val_if_fail (server != NULL, 0);
50     return server->priv->port;
51 }
52
53 static gboolean
54 read_cb (GSocket *socket, GIOCondition condition, VNCServer *server)
55 {
56     GError *error = NULL;
57     GSocket *client_socket;
58
59     client_socket = g_socket_accept (socket, NULL, &error);
60     if (error)
61         g_warning ("Failed to get connection from from VNC socket: %s", error->message);
62     g_clear_error (&error);
63
64     if (client_socket)
65     {
66         GInetSocketAddress *address;
67         gchar *hostname;
68
69         address = G_INET_SOCKET_ADDRESS (g_socket_get_remote_address (client_socket, NULL));
70         hostname = g_inet_address_to_string (g_inet_socket_address_get_address (address));
71         g_debug ("Got VNC connection from %s:%d", hostname, g_inet_socket_address_get_port (address));
72         g_free (hostname);
73
74         g_signal_emit (server, signals[NEW_CONNECTION], 0, client_socket);
75     }
76
77     return TRUE;
78 }
79
80 static GSocket *
81 open_tcp_socket (GSocketFamily family, guint port, GError **error)
82 {
83     GSocket *socket;
84     GSocketAddress *address;
85
86     socket = g_socket_new (family, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, error);
87     if (!socket)
88         return NULL;
89
90     address = g_inet_socket_address_new (g_inet_address_new_any (family), port);
91     if (!g_socket_bind (socket, address, TRUE, error) ||
92         !g_socket_listen (socket, error))
93     {
94         g_object_unref (socket);
95         return NULL;
96     }
97
98     return socket;
99 }
100
101 gboolean
102 vnc_server_start (VNCServer *server)
103 {
104     GSource *source;
105     GError *error = NULL;
106
107     g_return_val_if_fail (server != NULL, FALSE);
108
109     server->priv->socket = open_tcp_socket (G_SOCKET_FAMILY_IPV4, server->priv->port, &error);
110     if (error)
111         g_warning ("Failed to create IPv4 VNC socket: %s", error->message);
112     g_clear_error (&error);
113
114     if (server->priv->socket)
115     {
116         source = g_socket_create_source (server->priv->socket, G_IO_IN, NULL);
117         g_source_set_callback (source, (GSourceFunc) read_cb, server, NULL);
118         g_source_attach (source, NULL);
119     }
120
121     server->priv->socket6 = open_tcp_socket (G_SOCKET_FAMILY_IPV6, server->priv->port, &error);
122     if (error)
123         g_warning ("Failed to create IPv6 VNC socket: %s", error->message);
124     g_clear_error (&error);
125
126     if (server->priv->socket6)
127     {
128         source = g_socket_create_source (server->priv->socket6, G_IO_IN, NULL);
129         g_source_set_callback (source, (GSourceFunc) read_cb, server, NULL);
130         g_source_attach (source, NULL);
131     }
132
133     if (!server->priv->socket && !server->priv->socket6)
134         return FALSE;
135
136     return TRUE;
137 }
138
139 static void
140 vnc_server_init (VNCServer *server)
141 {
142     server->priv = G_TYPE_INSTANCE_GET_PRIVATE (server, VNC_SERVER_TYPE, VNCServerPrivate);
143     server->priv->port = 5900;
144 }
145
146 static void
147 vnc_server_finalize (GObject *object)
148 {
149     VNCServer *self;
150
151     self = VNC_SERVER (object);
152
153     if (self->priv->socket)
154         g_object_unref (self->priv->socket);
155     if (self->priv->socket6)
156         g_object_unref (self->priv->socket6);
157
158     G_OBJECT_CLASS (vnc_server_parent_class)->finalize (object);
159 }
160
161 static void
162 vnc_server_class_init (VNCServerClass *klass)
163 {
164     GObjectClass *object_class = G_OBJECT_CLASS (klass);
165
166     object_class->finalize = vnc_server_finalize;
167
168     g_type_class_add_private (klass, sizeof (VNCServerPrivate));
169
170     signals[NEW_CONNECTION] =
171         g_signal_new (VNC_SERVER_SIGNAL_NEW_CONNECTION,
172                       G_TYPE_FROM_CLASS (klass),
173                       G_SIGNAL_RUN_LAST,
174                       G_STRUCT_OFFSET (VNCServerClass, new_connection),
175                       NULL, NULL,
176                       NULL,
177                       G_TYPE_NONE, 1, G_TYPE_SOCKET);
178 }