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 typedef struct
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 } VNCServerPrivate;
33 
G_DEFINE_TYPE_WITH_PRIVATE(VNCServer,vnc_server,G_TYPE_OBJECT)34 G_DEFINE_TYPE_WITH_PRIVATE (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
vnc_server_set_port(VNCServer * server,guint port)43 vnc_server_set_port (VNCServer *server, guint port)
44 {
45     VNCServerPrivate *priv = vnc_server_get_instance_private (server);
46     g_return_if_fail (server != NULL);
47     priv->port = port;
48 }
49 
50 guint
vnc_server_get_port(VNCServer * server)51 vnc_server_get_port (VNCServer *server)
52 {
53     VNCServerPrivate *priv = vnc_server_get_instance_private (server);
54     g_return_val_if_fail (server != NULL, 0);
55     return priv->port;
56 }
57 
58 void
vnc_server_set_listen_address(VNCServer * server,const gchar * listen_address)59 vnc_server_set_listen_address (VNCServer *server, const gchar *listen_address)
60 {
61     VNCServerPrivate *priv = vnc_server_get_instance_private (server);
62 
63     g_return_if_fail (server != NULL);
64 
65     g_free (priv->listen_address);
66     priv->listen_address = g_strdup (listen_address);
67 }
68 
69 const gchar *
vnc_server_get_listen_address(VNCServer * server)70 vnc_server_get_listen_address (VNCServer *server)
71 {
72     VNCServerPrivate *priv = vnc_server_get_instance_private (server);
73     g_return_val_if_fail (server != NULL, NULL);
74     return priv->listen_address;
75 }
76 
77 static gboolean
read_cb(GSocket * socket,GIOCondition condition,VNCServer * server)78 read_cb (GSocket *socket, GIOCondition condition, VNCServer *server)
79 {
80     g_autoptr(GError) error = NULL;
81     g_autoptr(GSocket) client_socket = g_socket_accept (socket, NULL, &error);
82     if (error)
83         g_warning ("Failed to get connection from from VNC socket: %s", error->message);
84 
85     if (client_socket)
86     {
87         GInetSocketAddress *address = G_INET_SOCKET_ADDRESS (g_socket_get_remote_address (client_socket, NULL));
88         g_autofree gchar *hostname = g_inet_address_to_string (g_inet_socket_address_get_address (address));
89         g_debug ("Got VNC connection from %s:%d", hostname, g_inet_socket_address_get_port (address));
90 
91         g_signal_emit (server, signals[NEW_CONNECTION], 0, client_socket);
92     }
93 
94     return TRUE;
95 }
96 
97 static GSocket *
open_tcp_socket(GSocketFamily family,guint port,const gchar * listen_address,GError ** error)98 open_tcp_socket (GSocketFamily family, guint port, const gchar *listen_address, GError **error)
99 {
100     g_autoptr(GSocket) socket = g_socket_new (family, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, error);
101     if (!socket)
102         return NULL;
103 
104     g_autoptr(GSocketAddress) address = NULL;
105     if (listen_address)
106     {
107         GList *addresses = g_resolver_lookup_by_name (g_resolver_get_default (), listen_address, NULL, error);
108         if (!addresses)
109             return NULL;
110         address = g_inet_socket_address_new (addresses->data, port);
111         g_resolver_free_addresses (addresses);
112     }
113     else
114         address = g_inet_socket_address_new (g_inet_address_new_any (family), port);
115     if (!g_socket_bind (socket, address, TRUE, error) ||
116         !g_socket_listen (socket, error))
117         return NULL;
118 
119     return g_steal_pointer (&socket);
120 }
121 
122 gboolean
vnc_server_start(VNCServer * server)123 vnc_server_start (VNCServer *server)
124 {
125     VNCServerPrivate *priv = vnc_server_get_instance_private (server);
126 
127     g_return_val_if_fail (server != NULL, FALSE);
128 
129     g_autoptr(GError) ipv4_error = NULL;
130     priv->socket = open_tcp_socket (G_SOCKET_FAMILY_IPV4, priv->port, priv->listen_address, &ipv4_error);
131     if (ipv4_error)
132         g_warning ("Failed to create IPv4 VNC socket: %s", ipv4_error->message);
133 
134     if (priv->socket)
135     {
136         GSource *source = g_socket_create_source (priv->socket, G_IO_IN, NULL);
137         g_source_set_callback (source, (GSourceFunc) read_cb, server, NULL);
138         g_source_attach (source, NULL);
139     }
140 
141     g_autoptr(GError) ipv6_error = NULL;
142     priv->socket6 = open_tcp_socket (G_SOCKET_FAMILY_IPV6, priv->port, priv->listen_address, &ipv6_error);
143     if (ipv6_error)
144         g_warning ("Failed to create IPv6 VNC socket: %s", ipv6_error->message);
145 
146     if (priv->socket6)
147     {
148         GSource *source = g_socket_create_source (priv->socket6, G_IO_IN, NULL);
149         g_source_set_callback (source, (GSourceFunc) read_cb, server, NULL);
150         g_source_attach (source, NULL);
151     }
152 
153     if (!priv->socket && !priv->socket6)
154         return FALSE;
155 
156     return TRUE;
157 }
158 
159 static void
vnc_server_init(VNCServer * server)160 vnc_server_init (VNCServer *server)
161 {
162     VNCServerPrivate *priv = vnc_server_get_instance_private (server);
163     priv->port = 5900;
164 }
165 
166 static void
vnc_server_finalize(GObject * object)167 vnc_server_finalize (GObject *object)
168 {
169     VNCServer *self = VNC_SERVER (object);
170     VNCServerPrivate *priv = vnc_server_get_instance_private (self);
171 
172     g_clear_pointer (&priv->listen_address, g_free);
173     g_clear_object (&priv->socket);
174     g_clear_object (&priv->socket6);
175 
176     G_OBJECT_CLASS (vnc_server_parent_class)->finalize (object);
177 }
178 
179 static void
vnc_server_class_init(VNCServerClass * klass)180 vnc_server_class_init (VNCServerClass *klass)
181 {
182     GObjectClass *object_class = G_OBJECT_CLASS (klass);
183 
184     object_class->finalize = vnc_server_finalize;
185 
186     signals[NEW_CONNECTION] =
187         g_signal_new (VNC_SERVER_SIGNAL_NEW_CONNECTION,
188                       G_TYPE_FROM_CLASS (klass),
189                       G_SIGNAL_RUN_LAST,
190                       G_STRUCT_OFFSET (VNCServerClass, new_connection),
191                       NULL, NULL,
192                       NULL,
193                       G_TYPE_NONE, 1, G_TYPE_SOCKET);
194 }
195