Commit 9dbb5bfd authored by Brian Cameron's avatar Brian Cameron

A known issue with gdmdynamic is that when a display connects to the


        A known issue with gdmdynamic is that when a display connects to
        the server it generates the gdmdynamic "ADD" and "RELEASE" commands.
        On startup, hundreds of displays could send these commands at once
        and cause the server too be flooded with sockets requests.  Hammering
        the socket like this caused me to find and fix a number of problems
        that improve socket reliability for general GDM use.  I also enhanced
        gdmdynamic so it is more sensitive to the socket being busy and no
        longer overloads it, instead sleeping and retrying if necessary.  This
        allows gdmdynamic to work if there are hundreds of displays instead of
        just a dozen or so.

        * daemon/gdm.[ch]: Added new "SERVER_BUSY" sockets command so that
          gdmdynamic can sleep before starting new slaves if the daemon is
          already busy.
        * daemon/gdm-net.[ch]: Bump up MAX_CONNECTIONS from 10 to 15.  I notice
          that this improves performance significantly when hammering the
          daemon with connections.  Added better comments for this logic and
          now debug logs when a subconnection is thrown away.  New
          gdm_connection_is_server_busy function
        * daemon/display.c: Correct DYNAMIC_REMOVE so it works and fixes bug
          #326796.  Before it wasn't really removing the displays.
        * gui/gdmdynamic.c: Quite a bit of work to make gdmdynamic avoid
          flooding the server with sockets requests.  Now it sets sockets
          retries to 1 and manages sleeping and retries itself.
        * gui/gdmconfig.c: Added gdm_config_set_comm_retries so that slaves can
          specify how many retries they want the comm logic to use.
        * gui/gdmcomm.c: Now do_command returns NULL when it gets back "",
          which happens when a subconnection was dropped by the daemon.  This
          lets the slave try the connection again.   Now error messages are
          always logged, not just when debug is turned on.  Added
          gdmcomm_did_connection_fail and gdmcomm_set_allow_sleep so
          gdmdynamic can control the behavior of how the connection works.
        * gui/gdmcommon.c, gui/gdmchooser.c, gui/gdmlogin.c, gui/greeter/greeter.c:
          Fix gdm_common_fail so it doesn't generate compile errors when building
          with GCC.  Fixes bug #330480.
        * docs/C/gdm.xml: Cleaned up section that explains sockets commands so
          that they are in alphabetical order, added info about SERVER_BUSY
          and new gdmdynamic -s and -t options.
        * config/gdm.conf: Better description of how debug works, perhaps
          I just didn't like the word "spew".
---------------------------------------------------------------------
parent 441eb0bd
2006-02-09 Brian Cameron <brian.cameron@sun.com>
A known issue with gdmdynamic is that when a display connects to
the server it generates the gdmdynamic "ADD" and "RELEASE" commands.
On startup, hundreds of displays could send these commands at once
and cause the server too be flooded with sockets requests. Hammering
the socket like this caused me to find and fix a number of problems
that improve socket reliability for general GDM use. I also enhanced
gdmdynamic so it is more sensitive to the socket being busy and no
longer overloads it, instead sleeping and retrying if necessary. This
allows gdmdynamic to work if there are hundreds of displays instead of
just a dozen or so.
* daemon/gdm.[ch]: Added new "SERVER_BUSY" sockets command so that
gdmdynamic can sleep before starting new slaves if the daemon is
already busy.
* daemon/gdm-net.[ch]: Bump up MAX_CONNECTIONS from 10 to 15. I notice
that this improves performance significantly when hammering the
daemon with connections. Added better comments for this logic and
now debug logs when a subconnection is thrown away. New
gdm_connection_is_server_busy function
* daemon/display.c: Correct DYNAMIC_REMOVE so it works and fixes bug
#326796. Before it wasn't really removing the displays.
* gui/gdmdynamic.c: Quite a bit of work to make gdmdynamic avoid
flooding the server with sockets requests. Now it sets sockets
retries to 1 and manages sleeping and retries itself.
* gui/gdmconfig.c: Added gdm_config_set_comm_retries so that slaves can
specify how many retries they want the comm logic to use.
* gui/gdmcomm.c: Now do_command returns NULL when it gets back "",
which happens when a subconnection was dropped by the daemon. This
lets the slave try the connection again. Now error messages are
always logged, not just when debug is turned on. Added
gdmcomm_did_connection_fail and gdmcomm_set_allow_sleep so
gdmdynamic can control the behavior of how the connection works.
* gui/gdmcommon.c, gui/gdmchooser.c, gui/gdmlogin.c, gui/greeter/greeter.c:
Fix gdm_common_fail so it doesn't generate compile errors when building
with GCC. Fixes bug #330480.
* docs/C/gdm.xml: Cleaned up section that explains sockets commands so
that they are in alphabetical order, added info about SERVER_BUSY
and new gdmdynamic -s and -t options.
* config/gdm.conf: Better description of how debug works, perhaps
I just didn't like the word "spew".
2006-02-07 Brian Cameron <brian.cameron@sun.com>
* gui/gdmconfig.c: Return compiled in value if slave fails
......
......@@ -498,9 +498,10 @@ Multicast=false
#AllowAdd=true
[debug]
# This will enable debugging into the syslog, usually not necessary and it
# creates a LOT of spew of random stuff to the syslog. However it can be
# useful in determining when something is going very wrong.
# This will cause GDM to send debugging information to the system log, which
# will create a LOT of output. It is not recommended to turn this on for
# normal use, but it can be useful to determine the cause when GDM is not
# working properly.
Enable=false
# This will enable debug messages for accessibilty gesture listeners into the
# syslog. This includes output about key events, mouse button events, and
......
......@@ -368,7 +368,6 @@ gdm_display_manage (GdmDisplay *d)
*
* Stop services for a display
*/
void
gdm_display_unmanage (GdmDisplay *d)
{
......@@ -387,7 +386,7 @@ gdm_display_unmanage (GdmDisplay *d)
whack_old_slave (d, TRUE /* kill_connection */);
d->dispstat = DISPLAY_DEAD;
if (d->type != TYPE_STATIC)
if (d->type != TYPE_STATIC || d->removeconf)
gdm_display_dispose (d);
gdm_debug ("gdm_display_unmanage: Display stopped");
......
......@@ -37,8 +37,38 @@
#include "gdm-net.h"
#include "gdmconfig.h"
/* Kind of a weird setup, new connections whack old connections */
#define MAX_CONNECTIONS 10
/*
* 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 gdm.conf 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;
......@@ -74,6 +104,21 @@ struct _GdmConnection {
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)
{
......@@ -200,12 +245,13 @@ gdm_socket_handler (GIOChannel *source,
GIOCondition cond,
gpointer data)
{
int fd;
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;
......@@ -240,8 +286,18 @@ gdm_socket_handler (GIOChannel *source,
conn->subconnections = g_list_append (conn->subconnections, newconn);
conn->n_subconnections++;
if (conn->n_subconnections > MAX_CONNECTIONS) {
gdm_debug ("Closing connection, %d subconnections reached", MAX_CONNECTIONS);
/*
* 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) {
gdm_debug ("Closing connection, %d subconnections reached",
max_connections);
GdmConnection *old = conn->subconnections->data;
conn->subconnections =
g_list_remove (conn->subconnections, old);
......
......@@ -76,16 +76,17 @@ void gdm_connection_set_user_flags (GdmConnection *conn,
gdm_connection_set_user_flags (conn, _flags); \
}
GdmDisplay * gdm_connection_get_display (GdmConnection *conn);
void gdm_connection_set_display (GdmConnection *conn,
GdmDisplay *disp);
void gdm_kill_subconnections_with_display (GdmConnection *conn,
GdmDisplay *disp);
GdmDisplay * gdm_connection_get_display (GdmConnection *conn);
void gdm_connection_set_display (GdmConnection *conn,
GdmDisplay *disp);
int gdm_connection_is_server_busy (GdmConnection *conn);
void gdm_kill_subconnections_with_display (GdmConnection *conn,
GdmDisplay *disp);
int gdm_connection_get_message_count (GdmConnection *conn);
int gdm_connection_get_message_count (GdmConnection *conn);
void gdm_connection_close (GdmConnection *conn);
void gdm_connection_close (GdmConnection *conn);
#endif /* GDM_NET_H */
......
......@@ -76,10 +76,10 @@ extern GSList *displays;
/* Local functions */
static void gdm_handle_message (GdmConnection *conn,
const char *msg,
const gchar *msg,
gpointer data);
static void gdm_handle_user_message (GdmConnection *conn,
const char *msg,
const gchar *msg,
gpointer data);
static void gdm_daemonify (void);
static void gdm_safe_restart (void);
......@@ -87,13 +87,13 @@ static void gdm_try_logout_action (GdmDisplay *disp);
static void gdm_restart_now (void);
static void handle_flexi_server (GdmConnection *conn,
int type,
const char *server,
const gchar *server,
gboolean handled,
gboolean chooser,
const char *xnest_disp,
const gchar *xnest_disp,
uid_t xnest_uid,
const char *xnest_auth_file,
const char *xnest_cookie);
const gchar *xnest_auth_file,
const gchar *xnest_cookie);
/* Global vars */
gint xdmcp_sessions = 0; /* Number of remote sessions */
......@@ -118,10 +118,10 @@ GdmConnection *pipeconn = NULL; /* slavepipe (handled just like Fifo for compati
GdmConnection *unixconn = NULL; /* UNIX Socket connection */
int slave_fifo_pipe_fd = -1; /* the slavepipe connection */
unsigned char *gdm_global_cookie = NULL;
unsigned char *gdm_global_cookie = NULL;
unsigned char *gdm_global_bcookie = NULL;
char *gdm_charset = NULL;
gchar *gdm_charset = NULL;
int gdm_normal_runlevel = -1; /* runlevel on linux that gdm was started in */
......@@ -141,7 +141,7 @@ gboolean gdm_in_final_cleanup = FALSE;
GdmLogoutAction safe_logout_action = GDM_LOGOUT_ACTION_NONE;
/* set in the main function */
char **stored_argv = NULL;
gchar **stored_argv = NULL;
int stored_argc = 0;
extern gchar *config_file;
......@@ -741,8 +741,11 @@ gdm_cleanup_children (void)
if (d->servpid > 1)
kill (d->servpid, SIGTERM);
d->servpid = 0;
if (gdm_get_value_bool (GDM_KEY_DYNAMIC_XSERVERS)) /* XXX - This needs to be handled better */
gdm_server_whack_lockfile (d);
if (gdm_get_value_bool (GDM_KEY_DYNAMIC_XSERVERS)) {
/* XXX - This needs to be handled better */
gdm_server_whack_lockfile (d);
}
/* race avoider */
gdm_sleep_no_signal (1);
......@@ -2487,11 +2490,11 @@ dehex_cookie (const char *cookie, int *len)
/* This runs as the user who owns the file */
static gboolean
check_cookie (const char *file, const char *disp, const char *cookie)
check_cookie (const gchar *file, const gchar *disp, const gchar *cookie)
{
Xauth *xa;
char *number;
char *bcookie;
gchar *number;
gchar *bcookie;
int cookielen;
gboolean ret = FALSE;
int cnt = 0;
......@@ -2538,15 +2541,15 @@ check_cookie (const char *file, const char *disp, const char *cookie)
}
static void
handle_flexi_server (GdmConnection *conn, int type, const char *server,
handle_flexi_server (GdmConnection *conn, int type, const gchar *server,
gboolean handled,
gboolean chooser,
const char *xnest_disp, uid_t xnest_uid,
const char *xnest_auth_file,
const char *xnest_cookie)
const gchar *xnest_disp, uid_t xnest_uid,
const gchar *xnest_auth_file,
const gchar *xnest_cookie)
{
GdmDisplay *display;
char *bin;
gchar *bin;
uid_t server_uid = 0;
gdm_debug ("server: '%s'", server);
......@@ -2648,7 +2651,7 @@ handle_flexi_server (GdmConnection *conn, int type, const char *server,
if (type == TYPE_FLEXI_XNEST) {
GdmDisplay *parent;
char *disp, *p;
gchar *disp, *p;
gdm_assert (xnest_disp != NULL);
disp = g_strdup (xnest_disp);
......@@ -2693,12 +2696,13 @@ handle_flexi_server (GdmConnection *conn, int type, const char *server,
}
static void
handle_dynamic_server (GdmConnection *conn, int type, char *key)
handle_dynamic_server (GdmConnection *conn, int type, gchar *key)
{
GdmDisplay *disp;
int disp_num;
char *full;
char *val;
gchar *msg;
gchar *full;
gchar *val;
if (!(gdm_get_value_bool (GDM_KEY_DYNAMIC_XSERVERS))) {
gdm_connection_write (conn, "ERROR 200 Dynamic Displays not allowed\n");
......@@ -2711,8 +2715,13 @@ handle_dynamic_server (GdmConnection *conn, int type, char *key)
return;
}
if ((key == NULL) || (!(isdigit (*key)))) {
gdm_connection_write (conn, "ERROR 1 Bad display number\n");
if (key == NULL) {
gdm_connection_write (conn, "ERROR 1 Bad display number <NULL>\n");
return;
} else if ( !(isdigit (*key))) {
msg = g_strdup_printf ("ERROR 1 Bad display number <%s>\n", key);
gdm_connection_write (conn, msg);
g_free (msg);
return;
}
disp_num = atoi (key);
......@@ -2749,7 +2758,7 @@ handle_dynamic_server (GdmConnection *conn, int type, char *key)
if (disp_num > gdm_get_high_display_num ())
gdm_set_high_display_num (disp_num);
gdm_connection_write (conn, "OK\n");
gdm_connection_write (conn, "OK\n");
return;
}
......@@ -2769,7 +2778,8 @@ handle_dynamic_server (GdmConnection *conn, int type, char *key)
}
}
gdm_connection_write (conn, "ERROR 1 Bad display number\n");
msg = g_strdup_printf ("ERROR 1 Bad display number <%d>\n", disp_num);
gdm_connection_write (conn, msg);
return;
}
......@@ -2777,6 +2787,7 @@ handle_dynamic_server (GdmConnection *conn, int type, char *key)
/* cause the newly configured X servers to actually run */
GSList *li;
GSList *nli;
gboolean found = FALSE;
for (li = displays; li != NULL; li = nli) {
GdmDisplay *disp = li->data;
......@@ -2788,17 +2799,24 @@ handle_dynamic_server (GdmConnection *conn, int type, char *key)
if ( ! gdm_display_manage (disp)) {
gdm_display_unmanage (disp);
}
found = TRUE;
}
}
gdm_connection_write (conn, "OK\n");
if (found)
gdm_connection_write (conn, "OK\n");
else {
msg = g_strdup_printf ("ERROR 1 Bad display number <%d>\n", disp_num);
gdm_connection_write (conn, msg);
}
/* Now we wait for the server to start up (or not) */
return;
}
}
static void
gdm_handle_user_message (GdmConnection *conn, const char *msg, gpointer data)
gdm_handle_user_message (GdmConnection *conn, const gchar *msg, gpointer data)
{
gdm_debug ("Handling user message: '%s'", msg);
......@@ -2812,7 +2830,7 @@ gdm_handle_user_message (GdmConnection *conn, const char *msg, gpointer data)
if (strncmp (msg, GDM_SUP_AUTH_LOCAL " ",
strlen (GDM_SUP_AUTH_LOCAL " ")) == 0) {
GSList *li;
char *cookie = g_strdup
gchar *cookie = g_strdup
(&msg[strlen (GDM_SUP_AUTH_LOCAL " ")]);
g_strstrip (cookie);
if (strlen (cookie) != 16*2) /* 16 bytes in hex form */ {
......@@ -2839,7 +2857,7 @@ gdm_handle_user_message (GdmConnection *conn, const char *msg, gpointer data)
}
if (gdm_global_cookie != NULL &&
g_ascii_strcasecmp ((char *) gdm_global_cookie, cookie) == 0) {
g_ascii_strcasecmp ((gchar *) gdm_global_cookie, cookie) == 0) {
g_free (cookie);
GDM_CONNECTION_SET_USER_FLAG
(conn, GDM_SUP_FLAG_AUTH_GLOBAL);
......@@ -2870,8 +2888,8 @@ gdm_handle_user_message (GdmConnection *conn, const char *msg, gpointer data)
NULL, 0, NULL, NULL);
} else if (strncmp (msg, GDM_SUP_FLEXI_XSERVER " ",
strlen (GDM_SUP_FLEXI_XSERVER " ")) == 0) {
char *name;
const char *command = NULL;
gchar *name;
const gchar *command = NULL;
GdmXserver *svr;
/* Only allow locally authenticated connections */
......@@ -2916,7 +2934,7 @@ gdm_handle_user_message (GdmConnection *conn, const char *msg, gpointer data)
NULL, 0, NULL, NULL);
} else if (strncmp (msg, GDM_SUP_FLEXI_XNEST " ",
strlen (GDM_SUP_FLEXI_XNEST " ")) == 0) {
char *dispname = NULL, *xauthfile = NULL, *cookie = NULL;
gchar *dispname = NULL, *xauthfile = NULL, *cookie = NULL;
uid_t uid;
extract_dispname_uid_xauthfile_cookie (msg, &dispname, &uid,
......@@ -2953,7 +2971,7 @@ gdm_handle_user_message (GdmConnection *conn, const char *msg, gpointer data)
strlen (GDM_SUP_CONSOLE_SERVERS)) == 0)) {
GString *retMsg;
GSList *li;
const char *sep = " ";
const gchar *sep = " ";
char *key;
int msgLen=0;
......@@ -2993,7 +3011,7 @@ gdm_handle_user_message (GdmConnection *conn, const char *msg, gpointer data)
} else if (strcmp (msg, GDM_SUP_ALL_SERVERS) == 0) {
GString *msg;
GSList *li;
const char *sep = " ";
const gchar *sep = " ";
msg = g_string_new ("OK");
for (li = displays; li != NULL; li = li->next) {
......@@ -3018,9 +3036,9 @@ gdm_handle_user_message (GdmConnection *conn, const char *msg, gpointer data)
} else if (strncmp (msg, GDM_SUP_GET_SERVER_DETAILS " ",
strlen (GDM_SUP_GET_SERVER_DETAILS " ")) == 0) {
const char *server = &msg[strlen (GDM_SUP_GET_SERVER_DETAILS " ")];
const gchar *server = &msg[strlen (GDM_SUP_GET_SERVER_DETAILS " ")];
gchar **splitstr = g_strsplit (server, " ", 2);
GdmXserver *svr = gdm_find_xserver ((char *)splitstr[0]);
GdmXserver *svr = gdm_find_xserver ((gchar *)splitstr[0]);
if (svr != NULL) {
if (g_strcasecmp (splitstr[1], "ID") == 0)
......@@ -3066,7 +3084,7 @@ gdm_handle_user_message (GdmConnection *conn, const char *msg, gpointer data)
} else if (strcmp (msg, GDM_SUP_GREETERPIDS) == 0) {
GString *msg;
GSList *li;
const char *sep = " ";
const gchar *sep = " ";
msg = g_string_new ("OK");
for (li = displays; li != NULL; li = li->next) {
......@@ -3082,7 +3100,7 @@ gdm_handle_user_message (GdmConnection *conn, const char *msg, gpointer data)
g_string_free (msg, TRUE);
} else if (strncmp (msg, GDM_SUP_UPDATE_CONFIG " ",
strlen (GDM_SUP_UPDATE_CONFIG " ")) == 0) {
const char *key =
const gchar *key =
&msg[strlen (GDM_SUP_UPDATE_CONFIG " ")];
if (! gdm_update_config ((gchar *)key))
......@@ -3091,7 +3109,7 @@ gdm_handle_user_message (GdmConnection *conn, const char *msg, gpointer data)
gdm_connection_write (conn, "OK\n");
} else if (strncmp (msg, GDM_SUP_GET_CONFIG " ",
strlen (GDM_SUP_GET_CONFIG " ")) == 0) {
const char *key = &msg[strlen (GDM_SUP_GET_CONFIG " ")];
const gchar *key = &msg[strlen (GDM_SUP_GET_CONFIG " ")];
gchar *retval;
static gboolean done_prefetch = FALSE;
......@@ -3125,7 +3143,7 @@ gdm_handle_user_message (GdmConnection *conn, const char *msg, gpointer data)
gdm_connection_printf (conn, "OK %s\n", config_file);
g_string_free (msg, TRUE);
} else if (strcmp (msg, GDM_SUP_QUERY_LOGOUT_ACTION) == 0) {
const char *sep = " ";
const gchar *sep = " ";
GdmDisplay *disp;
GdmLogoutAction logout_action;
GString *msg;
......@@ -3175,7 +3193,7 @@ gdm_handle_user_message (GdmConnection *conn, const char *msg, gpointer data)
g_string_free (msg, TRUE);
} else if (strncmp (msg, GDM_SUP_SET_LOGOUT_ACTION " ",
strlen (GDM_SUP_SET_LOGOUT_ACTION " ")) == 0) {
const char *action =
const gchar *action =
&msg[strlen (GDM_SUP_SET_LOGOUT_ACTION " ")];
GdmDisplay *disp;
gboolean was_ok = FALSE;
......@@ -3227,7 +3245,7 @@ gdm_handle_user_message (GdmConnection *conn, const char *msg, gpointer data)
}
} else if (strncmp (msg, GDM_SUP_SET_SAFE_LOGOUT_ACTION " ",
strlen (GDM_SUP_SET_SAFE_LOGOUT_ACTION " ")) == 0) {
const char *action =
const gchar *action =
&msg[strlen (GDM_SUP_SET_SAFE_LOGOUT_ACTION " ")];
GdmDisplay *disp;
gboolean was_ok = FALSE;
......@@ -3328,7 +3346,7 @@ gdm_handle_user_message (GdmConnection *conn, const char *msg, gpointer data)
#endif
} else if (strncmp (msg, GDM_SUP_ADD_DYNAMIC_DISPLAY " ",
strlen (GDM_SUP_ADD_DYNAMIC_DISPLAY " ")) == 0) {
char *key;
gchar *key;
key = g_strdup (&msg[strlen (GDM_SUP_ADD_DYNAMIC_DISPLAY " ")]);
g_strstrip (key);
......@@ -3337,7 +3355,7 @@ gdm_handle_user_message (GdmConnection *conn, const char *msg, gpointer data)
} else if (strncmp (msg, GDM_SUP_REMOVE_DYNAMIC_DISPLAY " ",
strlen (GDM_SUP_REMOVE_DYNAMIC_DISPLAY " ")) == 0) {
char *key;
gchar *key;
key = g_strdup (&msg[strlen (GDM_SUP_REMOVE_DYNAMIC_DISPLAY " ")]);
g_strstrip (key);
......@@ -3347,7 +3365,7 @@ gdm_handle_user_message (GdmConnection *conn, const char *msg, gpointer data)
} else if (strncmp (msg, GDM_SUP_RELEASE_DYNAMIC_DISPLAYS " ",
strlen (GDM_SUP_RELEASE_DYNAMIC_DISPLAYS " ")) == 0) {
char *key;
gchar *key;
key = g_strdup (&msg[strlen (GDM_SUP_RELEASE_DYNAMIC_DISPLAYS " ")]);
g_strstrip (key);
......@@ -3356,6 +3374,11 @@ gdm_handle_user_message (GdmConnection *conn, const char *msg, gpointer data)
} else if (strcmp (msg, GDM_SUP_VERSION) == 0) {
gdm_connection_write (conn, "GDM " VERSION "\n");
} else if (strcmp (msg, GDM_SUP_SERVER_BUSY) == 0) {
if (gdm_connection_is_server_busy (unixconn))
gdm_connection_write (conn, "OK true\n");
else
gdm_connection_write (conn, "OK false\n");
} else if (strcmp (msg, GDM_SUP_CLOSE) == 0) {
gdm_connection_close (conn);
} else {
......
......@@ -1194,6 +1194,20 @@ void gdm_final_cleanup (void);
* 200 = Too many messages
* 999 = Unknown error
*/
#define GDM_SUP_SERVER_BUSY "SERVER_BUSY" /* None */
/* SERVER_BUSY: Returns true if half or more of the daemon's sockets are
* busy, false otherwise. Used by slave programs which want
* to ensure they do not overhwelm the server.
* Supported since: 2.13.0.8
* Arguments: None
* Answers:
* OK <value>
* ERROR <err number> <english error description>
* 0 = Not implemented
* 200 = Too many messages
* 999 = Unknown error
*/
#define GDM_SUP_GET_SERVER_DETAILS "GET_SERVER_DETAILS" /* <server> <key> */
#define GDM_SUP_CLOSE "CLOSE" /* None */
/* CLOSE: Close sockets connection
* Supported since: 2.2.4.0
......
......@@ -272,7 +272,7 @@
launched in a window in the user's current session. Nested displays
can be started even if not logged into the console and are started by
running the <command>gdmflexiserver -n</command> command. Flexible
displays are not restarted when the user session ends. Flexbile
displays are not restarted when the user session ends. Flexible
displays require virtual terminal (VT) support in the kernel, and will
not be available if not supported (such as on Solaris). Nested
displays require that the X server supports Xnest.
......@@ -484,7 +484,7 @@
<para>
If a user has no defined face image, GDM will use the
&quot;stock_person&quot; icon defined in the current GTK+ theme. If no
such image is defined, it will fallback to the iamge specified in the
such image is defined, it will fallback to the image specified in the
<filename>DefaultFace</filename> configuration option, normally
/usr/share/pixmaps/nobody.png.
</para>
......@@ -3843,24 +3843,28 @@ Language=cs_CZ.UTF-8
</para>
<screen>
VERSION
ADD_DYNAMIC_DISPLAY
ALL_SERVERS
ATTACHED_SERVERS
AUTH_LOCAL
FLEXI_XSERVER
CLOSE
FLEXI_XNEST
ATTACHED_SERVERS
ALL_SERVERS
GET_SERVER_LIST
GET_SERVER_DETAILS
FLEXI_XSERVER
GET_CONFIG
GET_CONFIG_FILE
UPDATE_CONFIG
GET_SERVER_LIST
GET_SERVER_DETAILS
GREETERPIDS
QUERY_LOGOUT_ACTION
QUERY_VT
RELEASE_DYNAMIC_DISPLAYS
REMOVE_DYNAMIC_DISPLAY
SERVER_BUSY
SET_LOGOUT_ACTION
SET_SAFE_LOGOUT_ACTION
QUERY_VT
SET_VT
CLOSE
UPDATE_CONFIG
VERSION
</screen>
<para>
......@@ -3868,20 +3872,86 @@ CLOSE
response format, and return codes.
</para>
<sect3 id="queryversion">
<title>VERSION</title>
<sect3 id="adddynamic">
<title>ADD_DYNAMIC_DISPLAY</title>
<screen>
VERSION: Query GDM version
Supported since: 2.2.4.0
ADD_DYNAMIC_DISPLAY: Create a new server definition that will
run on the specified display leaving, it
in DISPLAY_CONFIG state.
Supported since: 2.8.0.0
Arguments: &lt;display to run on&gt;=&lt;server&gt;
Where &lt;server&gt; is either a configuration named in the
GDM configuration or a literal command name.
Answers:
OK &lt;display&gt;
ERROR &lt;err number&gt; &lt;english error description&gt;
0 = Not implemented
2 = Existing display
3 = No server string
4 = Display startup failure
100 = Not authenticated
200 = Dynamic Displays not allowed
999 = Unknown error
</screen>
</sect3>
<sect3 id="allservers">
<title>ALL_SERVERS</title>
<screen>
ALL_SERVERS: List all displays, including console, remote, xnest.
This can, for example, be useful to figure out if
the display you are on is managed by the gdm daemon,
by seeing if it is in the list. It is also somewhat
like the 'w' command but for graphical sessions.
Supported since: 2.4.2.96
Arguments: None
Answers:
GDM &lt;gdm version&gt;
OK &lt;server&gt;;&lt;server&gt;;...
&lt;server&gt; is &lt;display&gt;,&lt;logged in user&gt;
&lt;logged in user&gt; can be empty in case no one logged in yet
ERROR &lt;err number&gt; &lt;english error description&gt;
0 = Not implemented
200 = Too many messages
999 = Unknown error
</screen>
</sect3>
<sect3 id="attachedservers">
<title>ATTACHED_SERVERS</title>
<screen>
ATTACHED_SERVERS: List all attached displays. Doesn't list XDMCP
and xnest non-attached displays.
Note: This command used to be named CONSOLE_SERVERS,
which is still recognized for backwards
compatibility. The optional pattern argument
is supported as of version 2.8.0.0.
Supported since: 2.2.4.0
Arguments: &lt;pattern&gt; (optional)
With no argument, all attached displays are returned. The optional
&lt;pattern&gt; is a string that may contain glob characters '*', '?', and
'[]'. Only displays that match the pattern will be returned.
Answers:
OK &lt;server&gt;;&lt;server&gt;;...
&lt;server&gt; is &lt;display&gt;,&lt;logged in user&gt;,&lt;vt or xnest display&gt;
&lt;logged in user&gt; can be empty in case no one logged
in yet, and &lt;vt&gt; can be -1 if it's not known or not
supported (on non-Linux for example). If the display is an
xnest display and is a console one (that is, it is an xnest
inside another console display) it is listed and instead of
vt, it lists the parent display in standard form.
ERROR &lt;err number&gt; &lt;english error description&gt;
1 = Not implemented
200 = Too many messages
999 = Unknown error
</screen>
</sect3>
<sect3 id="authlocal">
<title>AUTH_LOCAL</title>
<screen>
......@@ -3913,29 +3983,16 @@ Answers:
</screen>
</sect3>
<sect3 id="flexixserver">
<title>FLEXI_XSERVER</title>
<sect3 id="close">
<title>CLOSE</title>
<screen>
FLEXI_XSERVER: Start a new X flexible display. Only supported on
connection that passed AUTH_LOCAL
CLOSE: Close sockets connection
Supported since: 2.2.4.0
Arguments: &lt;xserver type&gt;
If no arguments, starts the standard X server
Answers:
OK &lt;display&gt;
ERROR &lt;err number&gt; &lt;english error description&gt;
0 = Not implemented
1 = No more flexi servers
2 = Startup errors
3 = X failed
4 = X too busy
6 = No server binary
100 = Not authenticated
200 = Too many messages
999 = Unknown error
Arguments: None
Answers: None
</screen>
</sect3>
<sect3 id="flexixnest">
<title>FLEXI_XNEST</title>
<screen>
......@@ -3975,169 +4032,29 @@ Answers:
</screen>
</sect3>