Back to index

lightdm  1.3.2
Classes | Defines | Enumerations | Functions | Variables
xdmcp-server.c File Reference
#include <stdlib.h>
#include <string.h>
#include <X11/X.h>
#include <X11/Xdmcp.h>
#include <gio/gio.h>
#include "ldm-marshal.h"
#include "xdmcp-server.h"
#include "xdmcp-protocol.h"
#include "xdmcp-session-private.h"
#include "xauthority.h"

Go to the source code of this file.

Classes

struct  XDMCPServerPrivate

Defines

#define HASXDMAUTH
#define MANAGE_TIMEOUT   126000

Enumerations

enum  { NEW_SESSION, LAST_SIGNAL }

Functions

 G_DEFINE_TYPE (XDMCPServer, xdmcp_server, G_TYPE_OBJECT)
XDMCPServerxdmcp_server_new (void)
void xdmcp_server_set_port (XDMCPServer *server, guint port)
guint xdmcp_server_get_port (XDMCPServer *server)
void xdmcp_server_set_hostname (XDMCPServer *server, const gchar *hostname)
const gchar * xdmcp_server_get_hostname (XDMCPServer *server)
void xdmcp_server_set_status (XDMCPServer *server, const gchar *status)
const gchar * xdmcp_server_get_status (XDMCPServer *server)
void xdmcp_server_set_key (XDMCPServer *server, const gchar *key)
static gboolean session_timeout_cb (XDMCPSession *session)
static XDMCPSessionadd_session (XDMCPServer *server)
static XDMCPSessionget_session (XDMCPServer *server, guint16 id)
static void send_packet (GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
static const gchar * get_authentication_name (XDMCPServer *server)
static void handle_query (XDMCPServer *server, GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
static guint8 atox (char c)
static void decode_key (const gchar *key, guint8 *data)
static void handle_request (XDMCPServer *server, GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
static void handle_manage (XDMCPServer *server, GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
static void handle_keep_alive (XDMCPServer *server, GSocket *socket, GSocketAddress *address, XDMCPPacket *packet)
static gboolean read_cb (GSocket *socket, GIOCondition condition, XDMCPServer *server)
static GSocket * open_udp_socket (GSocketFamily family, guint port, GError **error)
gboolean xdmcp_server_start (XDMCPServer *server)
static void xdmcp_server_init (XDMCPServer *server)
static void xdmcp_server_finalize (GObject *object)
static void xdmcp_server_class_init (XDMCPServerClass *klass)

Variables

static guint signals [LAST_SIGNAL] = { 0 }

Class Documentation

struct XDMCPServerPrivate

Definition at line 31 of file xdmcp-server.c.

Class Members
gchar * hostname
gchar * key
guint port
GHashTable * sessions
GSocket * socket
GSocket * socket6
gchar * status

Define Documentation

#define HASXDMAUTH

Definition at line 15 of file xdmcp-server.c.

#define MANAGE_TIMEOUT   126000

Definition at line 55 of file xdmcp-server.c.


Enumeration Type Documentation

anonymous enum
Enumerator:
NEW_SESSION 
LAST_SIGNAL 

Definition at line 25 of file xdmcp-server.c.


Function Documentation

static XDMCPSession* add_session ( XDMCPServer server) [static]

Definition at line 126 of file xdmcp-server.c.

{
    XDMCPSession *session;
    guint16 id;

    do
    {
        id = g_random_int () & 0xFFFFFFFF;
    } while (g_hash_table_lookup (server->priv->sessions, GINT_TO_POINTER ((gint) id)));

    session = xdmcp_session_new (id);
    session->priv->server = server;
    g_hash_table_insert (server->priv->sessions, GINT_TO_POINTER ((gint) id), g_object_ref (session));
    session->priv->inactive_timeout = g_timeout_add (MANAGE_TIMEOUT, (GSourceFunc) session_timeout_cb, session);

    return session;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static guint8 atox ( char  c) [static]

Definition at line 224 of file xdmcp-server.c.

{
    if (c >= '0' && c <= '9')
        return c - '0';
    if (c >= 'a' && c <= 'f')
        return c - 'a' + 10;
    if (c >= 'A' && c <= 'F')
        return c - 'A' + 10;
    return 0;
}

Here is the caller graph for this function:

static void decode_key ( const gchar *  key,
guint8 *  data 
) [static]

Definition at line 236 of file xdmcp-server.c.

{
    gint i;

    memset (data, 0, sizeof (data));
    if (strncmp (key, "0x", 2) == 0 || strncmp (key, "0X", 2) == 0)
    {
        for (i = 0; i < 8; i++)
        {
            if (key[i*2] == '\0')
                break;
            data[i] |= atox (key[i*2]) << 8;
            if (key[i*2+1] == '\0')
                break;
            data[i] |= atox (key[i*2+1]);
        }
    }
    else
    {
        for (i = 1; i < 8 && key[i-1]; i++)
           data[i] = key[i-1];
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

G_DEFINE_TYPE ( XDMCPServer  ,
xdmcp_server  ,
G_TYPE_OBJECT   
)
static const gchar* get_authentication_name ( XDMCPServer server) [static]

Definition at line 173 of file xdmcp-server.c.

{
    if (server->priv->key)
        return "XDM-AUTHENTICATION-1";
    else
        return "";
}

Here is the caller graph for this function:

static XDMCPSession* get_session ( XDMCPServer server,
guint16  id 
) [static]

Definition at line 145 of file xdmcp-server.c.

{
    return g_hash_table_lookup (server->priv->sessions, GINT_TO_POINTER ((gint) id));
}

Here is the caller graph for this function:

static void handle_keep_alive ( XDMCPServer server,
GSocket *  socket,
GSocketAddress *  address,
XDMCPPacket packet 
) [static]

Definition at line 537 of file xdmcp-server.c.

{
    XDMCPPacket *response;
    XDMCPSession *session;
    gboolean alive = FALSE;

    session = get_session (server, packet->KeepAlive.session_id);
    if (session)
        alive = TRUE; // FIXME: xdmcp_session_get_alive (session);

    response = xdmcp_packet_alloc (XDMCP_Alive);
    response->Alive.session_running = alive;
    response->Alive.session_id = alive ? packet->KeepAlive.session_id : 0;
    send_packet (socket, address, response);
    xdmcp_packet_free (response);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void handle_manage ( XDMCPServer server,
GSocket *  socket,
GSocketAddress *  address,
XDMCPPacket packet 
) [static]

Definition at line 475 of file xdmcp-server.c.

{
    XDMCPSession *session;
    gboolean result;

    session = get_session (server, packet->Manage.session_id);
    if (!session)
    {
        XDMCPPacket *response;

        response = xdmcp_packet_alloc (XDMCP_Refuse);
        response->Refuse.session_id = packet->Manage.session_id;
        send_packet (socket, address, response);
        xdmcp_packet_free (response);

        return;
    }

    /* Ignore duplicate requests */
    if (session->priv->started)
    {
        if (session->priv->display_number != packet->Manage.display_number ||
            strcmp (session->priv->display_class, packet->Manage.display_class) != 0)
            g_debug ("Ignoring duplicate Manage with different data");
        return;
    }

    /* Reject if has changed display number */
    if (packet->Manage.display_number != session->priv->display_number)
    {
        XDMCPPacket *response;

        g_debug ("Received Manage for display number %d, but Request was %d", packet->Manage.display_number, session->priv->display_number);
        response = xdmcp_packet_alloc (XDMCP_Refuse);
        response->Refuse.session_id = packet->Manage.session_id;
        send_packet (socket, address, response);
        xdmcp_packet_free (response);
    }

    session->priv->display_class = g_strdup (packet->Manage.display_class);

    g_signal_emit (server, signals[NEW_SESSION], 0, session, &result);
    if (result)
    {
        /* Cancel the inactive timer */
        g_source_remove (session->priv->inactive_timeout);

        session->priv->started = TRUE;
    }
    else
    {
        XDMCPPacket *response;

        response = xdmcp_packet_alloc (XDMCP_Failed);
        response->Failed.session_id = packet->Manage.session_id;
        response->Failed.status = g_strdup_printf ("Failed to connect to display :%d", packet->Manage.display_number);
        send_packet (socket, address, response);
        xdmcp_packet_free (response);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void handle_query ( XDMCPServer server,
GSocket *  socket,
GSocketAddress *  address,
XDMCPPacket packet 
) [static]

Definition at line 182 of file xdmcp-server.c.

{
    XDMCPPacket *response;
    gchar **i;
    gchar *authentication_name = NULL;

    /* If no authentication requested and we are configured for none then allow */
    if (packet->Query.authentication_names[0] == NULL && server->priv->key == NULL)
        authentication_name = "";

    for (i = packet->Query.authentication_names; *i; i++)
    {
        if (strcmp (*i, get_authentication_name (server)) == 0 && server->priv->key != NULL)
        {
            authentication_name = *i;
            break;
        }
    }

    if (authentication_name)
    {
        response = xdmcp_packet_alloc (XDMCP_Willing);
        response->Willing.authentication_name = g_strdup (authentication_name);
        response->Willing.hostname = g_strdup (server->priv->hostname);
        response->Willing.status = g_strdup (server->priv->status);
    }
    else
    {
        response = xdmcp_packet_alloc (XDMCP_Unwilling);
        response->Unwilling.hostname = g_strdup (server->priv->hostname);
        if (server->priv->key)
            response->Unwilling.status = g_strdup_printf ("No matching authentication, server requires %s", get_authentication_name (server));
        else
            response->Unwilling.status = g_strdup ("Server does not support authentication");
    }
  
    send_packet (socket, address, response);

    xdmcp_packet_free (response);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void handle_request ( XDMCPServer server,
GSocket *  socket,
GSocketAddress *  address,
XDMCPPacket packet 
) [static]

Definition at line 261 of file xdmcp-server.c.

{
    int i;
    XDMCPPacket *response;
    XDMCPSession *session;
    guint8 *authentication_data = NULL;
    gsize authentication_data_length = 0;
    gboolean match_authorization = FALSE;
    gchar *authorization_name;
    guint8 *authorization_data = NULL;
    gsize authorization_data_length = 0;
    guint8 *session_authorization_data = NULL;
    gsize session_authorization_data_length = 0;
    gchar **j;
    guint16 family;
    GInetAddress *xserver_address = NULL;
    gchar *display_number;
    XdmAuthKeyRec rho;

    /* Try and find an IPv6 address */
    for (i = 0; i < packet->Request.n_connections; i++)
    {
        XDMCPConnection *connection = &packet->Request.connections[i];
        if (connection->type == XAUTH_FAMILY_INTERNET6 && connection->address.length == 16)
        {
            family = connection->type;
            xserver_address = g_inet_address_new_from_bytes (connection->address.data, G_SOCKET_FAMILY_IPV6);

            /* We can't use link-local addresses, as we need to know what interface it is on */
            if (g_inet_address_get_is_link_local (xserver_address))
            {
                g_object_unref (xserver_address);
                xserver_address = NULL;
            }
            else
                break;
        }
    }

    /* If no IPv6 address, then try and find an IPv4 one */
    if (!xserver_address)
    {
        for (i = 0; i < packet->Request.n_connections; i++)
        {
            XDMCPConnection *connection = &packet->Request.connections[i];
            if (connection->type == XAUTH_FAMILY_INTERNET && connection->address.length == 4)
            {
                family = connection->type;
                xserver_address = g_inet_address_new_from_bytes (connection->address.data, G_SOCKET_FAMILY_IPV4);
                break;
            }
        }
    }

    /* Decline if haven't got an address we can connect on */
    if (!xserver_address)
    {
        response = xdmcp_packet_alloc (XDMCP_Decline);
        response->Decline.status = g_strdup ("No valid address found");
        response->Decline.authentication_name = g_strdup (packet->Request.authentication_name);
        response->Decline.authentication_data.data = authentication_data;
        response->Decline.authentication_data.length = authentication_data_length;
        send_packet (socket, address, response);
        xdmcp_packet_free (response);
        return;
    }
  
    /* Must be using our authentication scheme */
    if (strcmp (packet->Request.authentication_name, get_authentication_name (server)) != 0)
    {
        response = xdmcp_packet_alloc (XDMCP_Decline);
        if (server->priv->key)
            response->Decline.status = g_strdup_printf ("Server only supports %s authentication", get_authentication_name (server));
        else
            response->Decline.status = g_strdup ("Server does not support authentication");
        response->Decline.authentication_name = g_strdup ("");
        send_packet (socket, address, response);
        xdmcp_packet_free (response);
        return;
    }

    /* Perform requested authentication */
    if (server->priv->key)
    {
        guint8 input[8], key[8];

        memset (input, 0, 8);
        memcpy (input, packet->Request.authentication_data.data, packet->Request.authentication_data.length > 8 ? 8 : packet->Request.authentication_data.length);

        /* Setup key */
        decode_key (server->priv->key, key);

        /* Decode message from server */
        authentication_data = g_malloc (sizeof (guint8) * 8);
        authentication_data_length = 8;

        XdmcpUnwrap (input, key, rho.data, authentication_data_length);
        XdmcpIncrementKey (&rho);
        XdmcpWrap (rho.data, key, authentication_data, authentication_data_length);

        authorization_name = g_strdup ("XDM-AUTHORIZATION-1");
    }
    else
        authorization_name = g_strdup ("MIT-MAGIC-COOKIE-1");

    /* Check if they support our authorization */
    for (j = packet->Request.authorization_names; *j; j++)
    {
        if (strcmp (*j, authorization_name) == 0)
        {
             match_authorization = TRUE;
             break;
        }
    }

    /* Decline if don't support out authorization */
    if (!match_authorization)
    {
        response = xdmcp_packet_alloc (XDMCP_Decline);
        response->Decline.status = g_strdup_printf ("Server requires %s authorization", authorization_name);
        g_free (authorization_name);
        response->Decline.authentication_name = g_strdup (packet->Request.authentication_name);
        response->Decline.authentication_data.data = authentication_data;
        response->Decline.authentication_data.length = authentication_data_length;
        send_packet (socket, address, response);
        xdmcp_packet_free (response);
        return;
    }

    /* Perform requested authorization */
    if (server->priv->key)
    {
        gint i;
        guint8 key[8], session_key[8];

        /* Setup key */
        decode_key (server->priv->key, key);

        /* Generate a private session key */
        // FIXME: Pick a good DES key?
        session_key[0] = 0;
        for (i = 1; i < 8; i++)
            session_key[i] = g_random_int () & 0xFF;

        /* Encrypt the session key and send it to the server */
        authorization_data = g_malloc (8);
        authorization_data_length = 8;
        XdmcpWrap (session_key, key, authorization_data, authorization_data_length);

        /* Authorization data is the number received from the client followed by the private session key */
        session_authorization_data = g_malloc (16);
        session_authorization_data_length = 16;
        XdmcpDecrementKey (&rho);
        memcpy (session_authorization_data, rho.data, 8);
        memcpy (session_authorization_data + 8, session_key, 8);
    }
    else
    {
        XAuthority *auth;

        /* Data is the cookie */
        auth = xauth_new_cookie (XAUTH_FAMILY_WILD, NULL, 0, "");
        authorization_data = xauth_copy_authorization_data (auth);
        authorization_data_length = xauth_get_authorization_data_length (auth);
        session_authorization_data = xauth_copy_authorization_data (auth);
        session_authorization_data_length = xauth_get_authorization_data_length (auth);

        g_object_unref (auth);
    }

    session = add_session (server);
    session->priv->address = xserver_address;
    session->priv->display_number = packet->Request.display_number;
    display_number = g_strdup_printf ("%d", packet->Request.display_number);

    /* We need to check if this is the loopback address and set the authority
     * for a local connection if this is so as XCB treats "127.0.0.1" as local
     * always */
    if (g_inet_address_get_is_loopback (xserver_address))
    {
        gchar hostname[1024];
        gethostname (hostname, 1024);

        session->priv->authority = xauth_new (XAUTH_FAMILY_LOCAL,
                                              (guint8 *) hostname,
                                              strlen (hostname),
                                              display_number,
                                              authorization_name,
                                              session_authorization_data,
                                              session_authorization_data_length);
    }
    else
        session->priv->authority = xauth_new (family,
                                              g_inet_address_to_bytes (G_INET_ADDRESS (xserver_address)),
                                              g_inet_address_get_native_size (G_INET_ADDRESS (xserver_address)),
                                              display_number,
                                              authorization_name,
                                              session_authorization_data,
                                              session_authorization_data_length);
    g_free (display_number);

    response = xdmcp_packet_alloc (XDMCP_Accept);
    response->Accept.session_id = xdmcp_session_get_id (session);
    response->Accept.authentication_name = g_strdup (packet->Request.authentication_name);
    response->Accept.authentication_data.data = authentication_data;
    response->Accept.authentication_data.length = authentication_data_length;
    response->Accept.authorization_name = authorization_name;
    response->Accept.authorization_data.data = authorization_data;
    response->Accept.authorization_data.length = authorization_data_length;
    send_packet (socket, address, response);
    xdmcp_packet_free (response);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static GSocket* open_udp_socket ( GSocketFamily  family,
guint  port,
GError **  error 
) [static]

Definition at line 605 of file xdmcp-server.c.

{
    GSocket *socket;
    GSocketAddress *address;
    gboolean result;
  
    socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP, error);
    if (!socket)
        return NULL;

    address = g_inet_socket_address_new (g_inet_address_new_any (family), port);
    result = g_socket_bind (socket, address, TRUE, error);
    if (!result)
    {
        g_object_unref (socket);
        return NULL;
    }

    return socket;
}

Here is the caller graph for this function:

static gboolean read_cb ( GSocket *  socket,
GIOCondition  condition,
XDMCPServer server 
) [static]

Definition at line 555 of file xdmcp-server.c.

{
    GSocketAddress *address;
    gchar data[1024];
    GError *error = NULL;
    gssize n_read;

    n_read = g_socket_receive_from (socket, &address, data, 1024, NULL, &error);
    if (error)
        g_warning ("Failed to read from XDMCP socket: %s", error->message);
    g_clear_error (&error);

    if (n_read > 0)
    {
        XDMCPPacket *packet;

        packet = xdmcp_packet_decode ((guint8 *)data, n_read);
        if (packet)
        {        
            g_debug ("Got %s", xdmcp_packet_tostring (packet));

            switch (packet->opcode)
            {
            case XDMCP_BroadcastQuery:
            case XDMCP_Query:
            case XDMCP_IndirectQuery:
                handle_query (server, socket, address, packet);
                break;
            case XDMCP_Request:
                handle_request (server, socket, address, packet);
                break;
            case XDMCP_Manage:
                handle_manage (server, socket, address, packet);              
                break;
            case XDMCP_KeepAlive:
                handle_keep_alive (server, socket, address, packet);
                break;
            default:
                g_warning ("Got unexpected XDMCP packet %d", packet->opcode);
                break;
            }

            xdmcp_packet_free (packet);
        }
    }

    return TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void send_packet ( GSocket *  socket,
GSocketAddress *  address,
XDMCPPacket packet 
) [static]

Definition at line 151 of file xdmcp-server.c.

{
    guint8 data[1024];
    gssize n_written;

    g_debug ("Send %s", xdmcp_packet_tostring (packet));
              
    n_written = xdmcp_packet_encode (packet, data, 1024);
    if (n_written < 0)
      g_critical ("Failed to encode XDMCP packet");
    else
    {
        GError *error = NULL;

        g_socket_send_to (socket, address, (gchar *) data, n_written, NULL, &error);
        if (error)
            g_warning ("Error sending packet: %s", error->message);
        g_clear_error (&error);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static gboolean session_timeout_cb ( XDMCPSession session) [static]

Definition at line 118 of file xdmcp-server.c.

{
    g_debug ("Timing out unmanaged session %d", session->priv->id);
    g_hash_table_remove (session->priv->server->priv->sessions, GINT_TO_POINTER ((gint) session->priv->id));
    return FALSE;
}

Here is the caller graph for this function:

static void xdmcp_server_class_init ( XDMCPServerClass klass) [static]

Definition at line 695 of file xdmcp-server.c.

{
    GObjectClass *object_class = G_OBJECT_CLASS (klass);

    object_class->finalize = xdmcp_server_finalize;  

    g_type_class_add_private (klass, sizeof (XDMCPServerPrivate));

    signals[NEW_SESSION] =
        g_signal_new ("new-session",
                      G_TYPE_FROM_CLASS (klass),
                      G_SIGNAL_RUN_LAST,
                      G_STRUCT_OFFSET (XDMCPServerClass, new_session),
                      g_signal_accumulator_true_handled,
                      NULL,
                      ldm_marshal_BOOLEAN__OBJECT,
                      G_TYPE_BOOLEAN, 1, XDMCP_SESSION_TYPE);
}

Here is the call graph for this function:

static void xdmcp_server_finalize ( GObject *  object) [static]

Definition at line 676 of file xdmcp-server.c.

{
    XDMCPServer *self;

    self = XDMCP_SERVER (object);
  
    if (self->priv->socket)
        g_object_unref (self->priv->socket);
    if (self->priv->socket6)
        g_object_unref (self->priv->socket6);
    g_free (self->priv->hostname);
    g_free (self->priv->status);
    g_free (self->priv->key);
    g_hash_table_unref (self->priv->sessions);
  
    G_OBJECT_CLASS (xdmcp_server_parent_class)->finalize (object);  
}

Here is the caller graph for this function:

const gchar* xdmcp_server_get_hostname ( XDMCPServer server)

Definition at line 87 of file xdmcp-server.c.

{
    g_return_val_if_fail (server != NULL, NULL);
    return server->priv->hostname;
}
guint xdmcp_server_get_port ( XDMCPServer server)

Definition at line 71 of file xdmcp-server.c.

{
    g_return_val_if_fail (server != NULL, 0);
    return server->priv->port;
}

Here is the caller graph for this function:

const gchar* xdmcp_server_get_status ( XDMCPServer server)

Definition at line 103 of file xdmcp-server.c.

{
    g_return_val_if_fail (server != NULL, NULL);
    return server->priv->status;
}
static void xdmcp_server_init ( XDMCPServer server) [static]

Definition at line 665 of file xdmcp-server.c.

{
    server->priv = G_TYPE_INSTANCE_GET_PRIVATE (server, XDMCP_SERVER_TYPE, XDMCPServerPrivate);

    server->priv->port = XDM_UDP_PORT;
    server->priv->hostname = g_strdup ("");
    server->priv->status = g_strdup ("");
    server->priv->sessions = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
}

Definition at line 58 of file xdmcp-server.c.

{
    return g_object_new (XDMCP_SERVER_TYPE, NULL);
}

Here is the caller graph for this function:

void xdmcp_server_set_hostname ( XDMCPServer server,
const gchar *  hostname 
)

Definition at line 78 of file xdmcp-server.c.

{
    g_return_if_fail (server != NULL);

    g_free (server->priv->hostname);
    server->priv->hostname = g_strdup (hostname);
}
void xdmcp_server_set_key ( XDMCPServer server,
const gchar *  key 
)

Definition at line 110 of file xdmcp-server.c.

{
    g_return_if_fail (server != NULL);
    g_free (server->priv->key);
    server->priv->key = g_strdup (key);
}

Here is the caller graph for this function:

void xdmcp_server_set_port ( XDMCPServer server,
guint  port 
)

Definition at line 64 of file xdmcp-server.c.

{
    g_return_if_fail (server != NULL);
    server->priv->port = port;
}

Here is the caller graph for this function:

void xdmcp_server_set_status ( XDMCPServer server,
const gchar *  status 
)

Definition at line 94 of file xdmcp-server.c.

{
    g_return_if_fail (server != NULL);

    g_free (server->priv->status);
    server->priv->status = g_strdup (status);
}
gboolean xdmcp_server_start ( XDMCPServer server)

Definition at line 627 of file xdmcp-server.c.

{
    GSource *source;
    GError *error = NULL;

    g_return_val_if_fail (server != NULL, FALSE);
  
    server->priv->socket = open_udp_socket (G_SOCKET_FAMILY_IPV4, server->priv->port, &error);
    if (error)
        g_warning ("Failed to create IPv4 XDMCP socket: %s", error->message);
    g_clear_error (&error);
  
    if (server->priv->socket)
    {
        source = g_socket_create_source (server->priv->socket, G_IO_IN, NULL);
        g_source_set_callback (source, (GSourceFunc) read_cb, server, NULL);
        g_source_attach (source, NULL);
    }
    
    server->priv->socket6 = open_udp_socket (G_SOCKET_FAMILY_IPV6, server->priv->port, &error);
    if (error)
        g_warning ("Failed to create IPv6 XDMCP socket: %s", error->message);
    g_clear_error (&error);

    if (server->priv->socket6)
    {
        source = g_socket_create_source (server->priv->socket6, G_IO_IN, NULL);
        g_source_set_callback (source, (GSourceFunc) read_cb, server, NULL);
        g_source_attach (source, NULL);
    }

    if (!server->priv->socket && !server->priv->socket6)
        return FALSE;

    return TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

guint signals[LAST_SIGNAL] = { 0 } [static]

Definition at line 29 of file xdmcp-server.c.