diff options
Diffstat (limited to 'daemon/gdm-net.c')
-rw-r--r-- | daemon/gdm-net.c | 682 |
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 */ |