Back to index

lightdm  1.3.2
vnc-server.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2010-2011 Robert Ancell.
00003  * Author: Robert Ancell <robert.ancell@canonical.com>
00004  * 
00005  * This program is free software: you can redistribute it and/or modify it under
00006  * the terms of the GNU General Public License as published by the Free Software
00007  * Foundation, either version 3 of the License, or (at your option) any later
00008  * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
00009  * license.
00010  */
00011 
00012 #include <gio/gio.h>
00013 
00014 #include "vnc-server.h"
00015 
00016 enum {
00017     NEW_CONNECTION,
00018     LAST_SIGNAL
00019 };
00020 static guint signals[LAST_SIGNAL] = { 0 };
00021 
00022 struct VNCServerPrivate
00023 {
00024     /* Port to listen on */
00025     guint port;
00026 
00027     /* Listening sockets */
00028     GSocket *socket, *socket6;
00029 };
00030 
00031 G_DEFINE_TYPE (VNCServer, vnc_server, G_TYPE_OBJECT);
00032 
00033 VNCServer *
00034 vnc_server_new (void)
00035 {
00036     return g_object_new (VNC_SERVER_TYPE, NULL);
00037 }
00038 
00039 void
00040 vnc_server_set_port (VNCServer *server, guint port)
00041 {
00042     g_return_if_fail (server != NULL);
00043     server->priv->port = port;
00044 }
00045 
00046 guint
00047 vnc_server_get_port (VNCServer *server)
00048 {
00049     g_return_val_if_fail (server != NULL, 0);
00050     return server->priv->port;
00051 }
00052 
00053 static gboolean
00054 read_cb (GSocket *socket, GIOCondition condition, VNCServer *server)
00055 {
00056     GError *error = NULL;
00057     GSocket *client_socket;
00058 
00059     client_socket = g_socket_accept (socket, NULL, &error);
00060     if (error)
00061         g_warning ("Failed to get connection from from VNC socket: %s", error->message);
00062     g_clear_error (&error);
00063 
00064     if (client_socket)
00065     {
00066         GInetSocketAddress *address;
00067         gchar *hostname;
00068 
00069         address = G_INET_SOCKET_ADDRESS (g_socket_get_remote_address (client_socket, NULL));
00070         hostname = g_inet_address_to_string (g_inet_socket_address_get_address (address));
00071         g_debug ("Got VNC connection from %s:%d", hostname, g_inet_socket_address_get_port (address));
00072         g_free (hostname);
00073 
00074         g_signal_emit (server, signals[NEW_CONNECTION], 0, client_socket);
00075     }
00076 
00077     return TRUE;
00078 }
00079 
00080 static GSocket *
00081 open_tcp_socket (GSocketFamily family, guint port, GError **error)
00082 {
00083     GSocket *socket;
00084     GSocketAddress *address;
00085   
00086     socket = g_socket_new (family, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, error);
00087     if (!socket)
00088         return NULL;
00089 
00090     address = g_inet_socket_address_new (g_inet_address_new_any (family), port);
00091     if (!g_socket_bind (socket, address, TRUE, error) ||
00092         !g_socket_listen (socket, error))
00093     {
00094         g_object_unref (socket);
00095         return NULL;
00096     }
00097 
00098     return socket;
00099 }
00100 
00101 gboolean
00102 vnc_server_start (VNCServer *server)
00103 {
00104     GSource *source;
00105     GError *error = NULL;
00106 
00107     g_return_val_if_fail (server != NULL, FALSE);
00108   
00109     server->priv->socket = open_tcp_socket (G_SOCKET_FAMILY_IPV4, server->priv->port, &error);
00110     if (error)
00111         g_warning ("Failed to create IPv4 VNC socket: %s", error->message);
00112     g_clear_error (&error);
00113   
00114     if (server->priv->socket)
00115     {
00116         source = g_socket_create_source (server->priv->socket, G_IO_IN, NULL);
00117         g_source_set_callback (source, (GSourceFunc) read_cb, server, NULL);
00118         g_source_attach (source, NULL);
00119     }
00120     
00121     server->priv->socket6 = open_tcp_socket (G_SOCKET_FAMILY_IPV6, server->priv->port, &error);
00122     if (error)
00123         g_warning ("Failed to create IPv6 VNC socket: %s", error->message);
00124     g_clear_error (&error);
00125 
00126     if (server->priv->socket6)
00127     {
00128         source = g_socket_create_source (server->priv->socket6, G_IO_IN, NULL);
00129         g_source_set_callback (source, (GSourceFunc) read_cb, server, NULL);
00130         g_source_attach (source, NULL);
00131     }
00132 
00133     if (!server->priv->socket && !server->priv->socket6)
00134         return FALSE;
00135 
00136     return TRUE;
00137 }
00138 
00139 static void
00140 vnc_server_init (VNCServer *server)
00141 {
00142     server->priv = G_TYPE_INSTANCE_GET_PRIVATE (server, VNC_SERVER_TYPE, VNCServerPrivate);
00143     server->priv->port = 5900;
00144 }
00145 
00146 static void
00147 vnc_server_finalize (GObject *object)
00148 {
00149     VNCServer *self;
00150 
00151     self = VNC_SERVER (object);
00152   
00153     if (self->priv->socket)
00154         g_object_unref (self->priv->socket);
00155     if (self->priv->socket6)
00156         g_object_unref (self->priv->socket6);
00157   
00158     G_OBJECT_CLASS (vnc_server_parent_class)->finalize (object);  
00159 }
00160 
00161 static void
00162 vnc_server_class_init (VNCServerClass *klass)
00163 {
00164     GObjectClass *object_class = G_OBJECT_CLASS (klass);
00165 
00166     object_class->finalize = vnc_server_finalize;  
00167 
00168     g_type_class_add_private (klass, sizeof (VNCServerPrivate));
00169 
00170     signals[NEW_CONNECTION] =
00171         g_signal_new ("new-connection",
00172                       G_TYPE_FROM_CLASS (klass),
00173                       G_SIGNAL_RUN_LAST,
00174                       G_STRUCT_OFFSET (VNCServerClass, new_connection),
00175                       NULL, NULL,
00176                       g_cclosure_marshal_VOID__OBJECT,
00177                       G_TYPE_NONE, 1, G_TYPE_SOCKET);
00178 }