summaryrefslogtreecommitdiff
path: root/daemon/gdm-net.c
diff options
context:
space:
mode:
Diffstat (limited to 'daemon/gdm-net.c')
-rw-r--r--daemon/gdm-net.c682
1 files changed, 0 insertions, 682 deletions
diff --git a/daemon/gdm-net.c b/daemon/gdm-net.c
deleted file mode 100644
index 93a48dbe..00000000
--- a/daemon/gdm-net.c
+++ /dev/null
@@ -1,682 +0,0 @@
-/* GDM - The GNOME Display Manager
- * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "config.h"
-
-#include <strings.h>
-#include <unistd.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/un.h>
-#include <netdb.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <errno.h>
-
-#include <glib/gi18n.h>
-
-#include "gdm.h"
-#include "misc.h"
-#include "gdm-net.h"
-
-#include "gdm-common.h"
-#include "gdm-log.h"
-#include "gdm-daemon-config.h"
-
-/*
- * Kind of a weird setup, new connections whack old connections.
- *
- * We may want to allow tuning of the max connections, since
- * this number means that only a certain number of slaves can
- * talk to the daemon at once. Note that since new connections
- * whack old connections, this tends to cause traffic problems
- * if the daemon is really being hammered.
- *
- * This is because the slaves retry a failed connection 5 times,
- * though they are at least smart enough to sleep 1 second
- * between retries if the connection failed on the connect()
- * call. But, this means that throwing off a connection causes
- * that slave to come back in another second and try to
- * connect again. So if the daemon is really being hammered,
- * this just causes more traffic problems. It's really faster
- * to let each connection finish.
- *
- * This may cause problems for some setups (perhaps terminal
- * servers) where lots of connections may hit the server at once
- * and 15 connections may not be enough (especially since the
- * console login screen may also be using one of them). Perhaps
- * this number should be in configuration file so it can be
- * tuned by the end user?
- *
- * If, when you turn on debug, you notice messages like this
- * in the log, "Closing connection, x subconnections reached"
- * and some slaves are not working properly, then bumping this
- * number up is probably a reasonable fix if you can't simply
- * reduce the socket load the daemon must handle.
- */
-#define MAX_CONNECTIONS 15
-
-struct _GdmConnection {
- int fd;
- guint source;
- gboolean writable;
-
- GString *buffer;
-
- int message_count;
-
- gboolean nonblock;
-
- int close_level; /* 0 - normal
- 1 - no close, when called raise to 2
- 2 - close was requested */
-
- char *filename; /* unix socket or fifo filename */
-
- guint32 user_flags;
-
- GdmConnectionHandler handler;
- gpointer data;
- GDestroyNotify destroy_notify;
-
- gpointer close_data;
- GDestroyNotify close_notify;
-
- GdmConnection *parent;
-
- GList *subconnections;
- int n_subconnections;
-
- GdmDisplay *disp;
-};
-
-int
-gdm_connection_is_server_busy (GdmConnection *conn) {
- int max_connections = MAX_CONNECTIONS;
-
- if (conn->n_subconnections >= (max_connections / 2)) {
- gdm_debug ("Connections is %d, max is %d, busy TRUE",
- conn->n_subconnections, max_connections);
- return TRUE;
- } else {
- gdm_debug ("Connections is %d, max is %d, busy FALSE",
- conn->n_subconnections, max_connections);
- return FALSE;
- }
-}
-
-static gboolean
-close_if_needed (GdmConnection *conn, GIOCondition cond, gboolean error)
-{
- /* non-subconnections are never closed */
- if (conn->parent == NULL)
- return TRUE;
-
- if (cond & G_IO_ERR ||
- cond & G_IO_HUP || error) {
- if (cond & G_IO_ERR)
- gdm_debug ("close_if_needed: Got G_IO_ERR on %d", conn->fd);
- if (cond & G_IO_HUP)
- gdm_debug ("close_if_needed: Got G_IO_HUP on %d", conn->fd);
- if (error)
- gdm_debug ("close_if_needed: Got error on %d", conn->fd);
- conn->source = 0;
- gdm_connection_close (conn);
- return FALSE;
- }
- return TRUE;
-}
-
-static gboolean
-gdm_connection_handler (GIOChannel *source,
- GIOCondition cond,
- gpointer data)
-{
- GdmConnection *conn = data;
- char buf[PIPE_SIZE];
- char *p;
- size_t len;
-
- if ( ! (cond & G_IO_IN))
- return close_if_needed (conn, cond, FALSE);
-
- VE_IGNORE_EINTR (len = read (conn->fd, buf, sizeof (buf) -1));
- if (len <= 0)
- return close_if_needed (conn, cond, TRUE);
-
- buf[len] = '\0';
-
- if (conn->buffer == NULL)
- conn->buffer = g_string_new (NULL);
-
- for (p = buf; *p != '\0'; p++) {
- if (*p == '\r' ||
- (*p == '\n' &&
- ve_string_empty (conn->buffer->str)))
- /*ignore \r or empty lines*/
- continue;
- if (*p == '\n' ||
- /* cut lines short at 4096 to prevent DoS attacks */
- conn->buffer->len > 4096) {
- conn->close_level = 1;
- conn->message_count++;
- conn->handler (conn, conn->buffer->str,
- conn->data);
- if (conn->close_level == 2) {
- conn->close_level = 0;
- conn->source = 0;
- gdm_connection_close (conn);
- return FALSE;
- }
- conn->close_level = 0;
- g_string_truncate (conn->buffer, 0);
- } else {
- g_string_append_c (conn->buffer, *p);
- }
- }
-
- return close_if_needed (conn, cond, FALSE);
-}
-
-gboolean
-gdm_connection_is_writable (GdmConnection *conn)
-{
- g_return_val_if_fail (conn != NULL, FALSE);
-
- return conn->writable;
-}
-
-gboolean
-gdm_connection_write (GdmConnection *conn, const char *str)
-{
- int ret;
- int save_errno;
- int flags = 0;
-#ifndef MSG_NOSIGNAL
- void (*old_handler)(int);
-#endif
-
- g_return_val_if_fail (conn != NULL, FALSE);
- g_return_val_if_fail (str != NULL, FALSE);
-
- if G_UNLIKELY ( ! conn->writable)
- return FALSE;
-
-#ifdef MSG_DONTWAIT
- if (conn->nonblock)
- flags |= MSG_DONTWAIT;
-#endif
-
-#ifdef MSG_NOSIGNAL
- VE_IGNORE_EINTR (ret = send (conn->fd, str, strlen (str), MSG_NOSIGNAL | flags));
- save_errno = errno;
-#else
- old_handler = signal (SIGPIPE, SIG_IGN);
- VE_IGNORE_EINTR (ret = send (conn->fd, str, strlen (str), flags));
- save_errno = errno;
- signal (SIGPIPE, old_handler);
-#endif
-
- /* just so that 'signal' doesn't whack it */
- errno = save_errno;
-
- if G_UNLIKELY (ret < 0)
- return FALSE;
- else
- return TRUE;
-}
-
-static gboolean
-gdm_socket_handler (GIOChannel *source,
- GIOCondition cond,
- gpointer data)
-{
- GIOChannel *unixchan;
- GdmConnection *conn = data;
- GdmConnection *newconn;
- struct sockaddr_un addr;
- socklen_t addr_size = sizeof (addr);
- int fd;
- int max_connections;
-
- if ( ! (cond & G_IO_IN))
- return TRUE;
-
- VE_IGNORE_EINTR (fd = accept (conn->fd,
- (struct sockaddr *)&addr,
- &addr_size));
- if G_UNLIKELY (fd < 0) {
- gdm_debug ("gdm_socket_handler: Rejecting connection");
- return TRUE;
- }
-
- gdm_debug ("gdm_socket_handler: Accepting new connection fd %d", fd);
-
- newconn = g_new0 (GdmConnection, 1);
- newconn->disp = NULL;
- newconn->message_count = 0;
- newconn->nonblock = conn->nonblock;
- newconn->close_level = 0;
- newconn->fd = fd;
- newconn->writable = TRUE;
- newconn->filename = NULL;
- newconn->user_flags = 0;
- newconn->buffer = NULL;
- newconn->parent = conn;
- newconn->subconnections = NULL;
- newconn->n_subconnections = 0;
- newconn->handler = conn->handler;
- newconn->data = conn->data;
- newconn->destroy_notify = NULL; /* the data belongs to
- parent connection */
-
- conn->subconnections = g_list_append (conn->subconnections, newconn);
- conn->n_subconnections++;
-
- /*
- * When dynamix servers is turned on, the daemon can be flooded with
- * requests and closing a subconnection will typically make the client
- * just try and connect again, and worsen the flooding problem. When
- * using dynamic servers, allow more clients to connect at once.
- */
- max_connections = MAX_CONNECTIONS;
-
- if (conn->n_subconnections > max_connections) {
- GdmConnection *old;
- gdm_debug ("Closing connection, %d subconnections reached",
- max_connections);
- old = conn->subconnections->data;
- conn->subconnections =
- g_list_remove (conn->subconnections, old);
- gdm_connection_close (old);
- }
-
- unixchan = g_io_channel_unix_new (newconn->fd);
- g_io_channel_set_encoding (unixchan, NULL, NULL);
- g_io_channel_set_buffered (unixchan, FALSE);
-
- newconn->source = g_io_add_watch_full
- (unixchan, G_PRIORITY_DEFAULT,
- G_IO_IN|G_IO_PRI|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
- gdm_connection_handler, newconn, NULL);
- g_io_channel_unref (unixchan);
-
- return TRUE;
-}
-
-GdmConnection *
-gdm_connection_open_unix (const char *sockname, mode_t mode)
-{
- GIOChannel *unixchan;
- GdmConnection *conn;
- struct sockaddr_un addr;
- int fd;
- int try_again_attempts = 1000;
-
- fd = socket (AF_UNIX, SOCK_STREAM, 0);
- if G_UNLIKELY (fd < 0) {
- gdm_error (_("%s: Could not make socket"),
- "gdm_connection_open_unix");
- return NULL;
- }
-
-try_again:
- /* this is all for creating sockets in /tmp/ safely */
- VE_IGNORE_EINTR (g_unlink (sockname));
- if G_UNLIKELY (errno == EISDIR ||
- errno == EPERM) {
- /* likely a directory, someone's playing tricks on us */
- char *newname = NULL;
- do {
- g_free (newname);
- newname = g_strdup_printf ("%s-renamed-%u",
- sockname,
- (guint)g_random_int ());
- } while (g_access (newname, F_OK) == 0);
- VE_IGNORE_EINTR (g_rename (sockname, newname));
- if G_UNLIKELY (errno != 0)
- try_again_attempts = 0;
- g_free (newname);
- } else if G_UNLIKELY (errno != 0) {
- try_again_attempts = 0;
- }
-
- memset (&addr, 0, sizeof (addr));
- strcpy (addr.sun_path, sockname);
- addr.sun_family = AF_UNIX;
- if G_UNLIKELY (bind (fd,
- (struct sockaddr *) &addr, sizeof (addr)) < 0) {
- gdm_error (_("%s: Could not bind socket"),
- "gdm_connection_open_unix");
- try_again_attempts --;
- /* someone is being evil on us */
- if (errno == EADDRINUSE && try_again_attempts >= 0)
- goto try_again;
- VE_IGNORE_EINTR (close (fd));
- return NULL;
- }
-
- VE_IGNORE_EINTR (g_chmod (sockname, mode));
-
- conn = g_new0 (GdmConnection, 1);
- conn->disp = NULL;
- conn->message_count = 0;
- conn->nonblock = FALSE;
- conn->close_level = 0;
- conn->fd = fd;
- conn->writable = FALSE;
- conn->buffer = NULL;
- conn->filename = g_strdup (sockname);
- conn->user_flags = 0;
- conn->parent = NULL;
- conn->subconnections = NULL;
- conn->n_subconnections = 0;
-
- unixchan = g_io_channel_unix_new (conn->fd);
- g_io_channel_set_encoding (unixchan, NULL, NULL);
- g_io_channel_set_buffered (unixchan, FALSE);
-
- conn->source = g_io_add_watch_full
- (unixchan, G_PRIORITY_DEFAULT,
- G_IO_IN|G_IO_PRI|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
- gdm_socket_handler, conn, NULL);
- g_io_channel_unref (unixchan);
-
- listen (fd, 5);
-
- return conn;
-}
-
-GdmConnection *
-gdm_connection_open_fd (int fd)
-{
- GIOChannel *unixchan;
- GdmConnection *conn;
-
- g_return_val_if_fail (fd >= 0, NULL);
-
- conn = g_new0 (GdmConnection, 1);
- conn->disp = NULL;
- conn->message_count = 0;
- conn->nonblock = FALSE;
- conn->close_level = 0;
- conn->fd = fd;
- conn->writable = FALSE;
- conn->buffer = NULL;
- conn->filename = NULL;
- conn->user_flags = 0;
- conn->parent = NULL;
- conn->subconnections = NULL;
- conn->n_subconnections = 0;
-
- unixchan = g_io_channel_unix_new (conn->fd);
- g_io_channel_set_encoding (unixchan, NULL, NULL);
- g_io_channel_set_buffered (unixchan, FALSE);
-
- conn->source = g_io_add_watch_full
- (unixchan, G_PRIORITY_DEFAULT,
- G_IO_IN|G_IO_PRI|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
- gdm_connection_handler, conn, NULL);
- g_io_channel_unref (unixchan);
-
- return conn;
-}
-
-GdmConnection *
-gdm_connection_open_fifo (const char *fifo, mode_t mode)
-{
- GIOChannel *fifochan;
- GdmConnection *conn;
- int fd;
-
- VE_IGNORE_EINTR (g_unlink (fifo));
-
- if G_UNLIKELY (mkfifo (fifo, 0660) < 0) {
- gdm_error (_("%s: Could not make FIFO"),
- "gdm_connection_open_fifo");
- return NULL;
- }
-
- fd = open (fifo, O_RDWR); /* Open with write to avoid EOF */
-
- if G_UNLIKELY (fd < 0) {
- gdm_error (_("%s: Could not open FIFO"),
- "gdm_connection_open_fifo");
- return NULL;
- }
-
- VE_IGNORE_EINTR (g_chmod (fifo, mode));
-
- conn = g_new0 (GdmConnection, 1);
- conn->disp = NULL;
- conn->message_count = 0;
- conn->nonblock = FALSE;
- conn->close_level = 0;
- conn->fd = fd;
- conn->writable = FALSE;
- conn->buffer = NULL;
- conn->filename = g_strdup (fifo);
- conn->user_flags = 0;
- conn->parent = NULL;
- conn->subconnections = NULL;
- conn->n_subconnections = 0;
-
- fifochan = g_io_channel_unix_new (conn->fd);
- g_io_channel_set_encoding (fifochan, NULL, NULL);
- g_io_channel_set_buffered (fifochan, FALSE);
-
- conn->source = g_io_add_watch_full
- (fifochan, G_PRIORITY_DEFAULT,
- G_IO_IN|G_IO_PRI|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
- gdm_connection_handler, conn, NULL);
- g_io_channel_unref (fifochan);
-
- return conn;
-}
-
-void
-gdm_connection_set_handler (GdmConnection *conn,
- GdmConnectionHandler handler,
- gpointer data,
- GDestroyNotify destroy_notify)
-{
- g_return_if_fail (conn != NULL);
-
- if (conn->destroy_notify != NULL)
- conn->destroy_notify (conn->data);
-
- conn->handler = handler;
- conn->data = data;
- conn->destroy_notify = destroy_notify;
-}
-
-guint32
-gdm_connection_get_user_flags (GdmConnection *conn)
-{
- g_return_val_if_fail (conn != NULL, 0);
-
- return conn->user_flags;
-}
-
-void
-gdm_connection_set_user_flags (GdmConnection *conn,
- guint32 flags)
-{
- g_return_if_fail (conn != NULL);
-
- conn->user_flags = flags;
-}
-
-void
-gdm_connection_close (GdmConnection *conn)
-{
- GList *list;
-
- g_return_if_fail (conn != NULL);
-
- if (conn->close_level > 0) {
- /* flag that close was requested */
- conn->close_level = 2;
- return;
- }
-
- if (conn->close_notify != NULL) {
- conn->close_notify (conn->close_data);
- conn->close_notify = NULL;
- }
- conn->close_data = NULL;
-
- if (conn->buffer != NULL) {
- g_string_free (conn->buffer, TRUE);
- conn->buffer = NULL;
- }
-
- if (conn->parent != NULL) {
- conn->parent->subconnections =
- g_list_remove (conn->parent->subconnections, conn);
- /* This is evil a bit, but safe, whereas -- would not be */
- conn->parent->n_subconnections =
- g_list_length (conn->parent->subconnections);
- conn->parent = NULL;
- }
-
- list = conn->subconnections;
- conn->subconnections = NULL;
- g_list_foreach (list, (GFunc) gdm_connection_close, NULL);
- g_list_free (list);
-
- if (conn->destroy_notify != NULL) {
- conn->destroy_notify (conn->data);
- conn->destroy_notify = NULL;
- }
- conn->data = NULL;
-
- if (conn->source > 0) {
- g_source_remove (conn->source);
- conn->source = 0;
- }
-
- if (conn->fd > 0) {
- VE_IGNORE_EINTR (close (conn->fd));
- conn->fd = -1;
- }
-
- g_free (conn->filename);
- conn->filename = NULL;
-
- g_free (conn);
-}
-
-void
-gdm_connection_set_close_notify (GdmConnection *conn,
- gpointer close_data,
- GDestroyNotify close_notify)
-{
- g_return_if_fail (conn != NULL);
-
- if (conn->close_notify != NULL)
- conn->close_notify (conn->close_data);
-
- conn->close_data = close_data;
- conn->close_notify = close_notify;
-}
-
-gboolean
-gdm_connection_printf (GdmConnection *conn, const gchar *format, ...)
-{
- va_list args;
- gboolean ret;
- gchar *s;
-
- va_start (args, format);
- s = g_strdup_vprintf (format, args);
- va_end (args);
-
- ret = gdm_connection_write (conn, s);
-
- g_free (s);
-
- return ret;
-}
-
-int
-gdm_connection_get_message_count (GdmConnection *conn)
-{
- g_return_val_if_fail (conn != NULL, -1);
- return conn->message_count;
-}
-
-gboolean
-gdm_connection_get_nonblock (GdmConnection *conn)
-{
- g_return_val_if_fail (conn != NULL, FALSE);
- return conn->nonblock;
-}
-
-void
-gdm_connection_set_nonblock (GdmConnection *conn,
- gboolean nonblock)
-{
- g_return_if_fail (conn != NULL);
- conn->nonblock = nonblock;
-}
-
-GdmDisplay *
-gdm_connection_get_display (GdmConnection *conn)
-{
- g_return_val_if_fail (conn != NULL, NULL);
- return conn->disp;
-}
-
-void
-gdm_connection_set_display (GdmConnection *conn,
- GdmDisplay *disp)
-{
- g_return_if_fail (conn != NULL);
- conn->disp = disp;
-}
-
-void
-gdm_kill_subconnections_with_display (GdmConnection *conn,
- GdmDisplay *disp)
-{
- GList *subs;
-
- g_return_if_fail (conn != NULL);
- g_return_if_fail (disp != NULL);
-
- subs = conn->subconnections;
- while (subs != NULL) {
- GdmConnection *subcon = subs->data;
- if (subcon->disp == disp) {
- subcon->disp = NULL;
- conn->subconnections =
- g_list_remove (conn->subconnections, subcon);
- gdm_connection_close (subcon);
- subs = conn->subconnections;
- } else {
- subs = subs->next;
- }
- }
-}
-
-/* EOF */