sensing X connection failure/timeout
Yann Droneaud
ydroneaud at mandriva.com
Wed Sep 30 01:56:32 PDT 2009
Le mardi 29 septembre 2009 à 13:08 -0500, Xavier Toth a écrit :
> I'm displaying clients on a remote X server and if I power the X
> server box or pull the network cable some of the clients never
> terminate. Some clients (fbpanel and gnome-screensaver in particular)
> terminate and write "Fatal IO error 110 (Connection timeout) on X
> server <ip address>" to stderr, openbox the window manager we are
> using does not ever realize that the server is gone. Looking at the
> openbox main loop code:
>
[...]
> I see that if there are no X event it does a select on an fd set
> initialized as follows:
>
[...]
> with a wait of NULL (infinite) and it never returns.
>
> What is the proper way to determine that a remote server connection
> has failed or timed out?
>
Once upon a time, I wrote this. As other good story, this one start by:
while(1)
{
/** wait for a read event
* there's no need to check for exception condition:
* there's none, see man 7 socket
*
* it would be better to use ppoll(), but it's not widely available
*
*/
sigemptyset(&signal_mask);
n = pselect(FD_SETSIZE, &fdset, NULL, NULL,
NULL, &signal_mask);
if (n < 0) {
/* interrupted, OK, just retry */
if (errno == EINTR || errno == EAGAIN || errno == EINPROGRESS)
continue;
/* real error, retry */
/* XXX: count number of error */
DPRINTF( "select() failed: %s\n", strerror(errno));
continue;
}
if (n == 0) {
/* timeout ! */
continue;
}
if (FD_ISSET(XConnectionNumber(display), &fdset)) {
/* read some events (do not flush output buffer) */
if (XEventsQueued(display, QueuedAfterReading)) {
do {
/* extract an event from the input queue */
XNextEvent(display, &e);
printf("event %d\n",
e.type);
/* XXX process the event */
} while(XEventsQueued(display, QueuedAlready));
/*
* send the output data,
* since XNextEvent will never do it for us,
* because the input queue will never be empty
* when it is called.
*
*/
XFlush(display);
} else {
/* read condition, but no event, check for EOF */
struct pollfd pfd;
pfd.fd = XConnectionNumber(display);
pfd.events = POLLIN;
pfd.revents = 0;
n = poll(&pfd, 1, 0);
if (n <= 0) {
DPRINTF("poll() failed: %s\n", strerror(errno));
}
if (n == 1) {
DPRINTF("poll() returned 0x%04x\n", (unsigned int)
pfd.revents);
if (pfd.revents & POLLNVAL) {
DPRINTF("poll() failed: invalid file descripor\n");
}
if (pfd.revents & POLLERR) {
DPRINTF("poll() returned POLLERR\n");
}
if (pfd.revents & POLLHUP) {
DPRINTF("poll() returned POLLHUP\n");
}
if (pfd.revents & POLLIN) {
DPRINTF("poll() returned POLLIN\n");
}
if (pfd.revents & POLLHUP) {
int pending = 0;
/* if no read condition or no data in the socket: EOF */
if (!(pfd.revents & POLLIN) ||
(ioctl(XConnectionNumber(display), FIONREAD, &pending) !
= 0 ||
pending == 0)) {
/* connection closed */
#if 0
XSync(display, True); /* just go crazy: process errors,
discard queues */
XCloseDisplay(display);
#endif
/*
* can't do more than that:
* calling XSync() or XCloseDisplay() generate SIGPIPE
* since they wrote on the connexion regardless of the
status
*
* but, it's at least better than the default error
function
*
*/
fprintf(stderr, "Lost connexion to X server\n");
close(XConnectionNumber(display));
exit(0);
}
}
}
}
}
But beware of signals hidden in the woods.
Regards.
--
Yann Droneaud
More information about the xorg
mailing list