KasmVNC/unix/xserver/hw/vnc/vncBlockHandler.c
2020-09-20 12:16:44 +00:00

297 lines
6.4 KiB
C

/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
* Copyright 2011-2014 Pierre Ossman for Cendio AB
*
* This 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 software 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 software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <errno.h>
#include <X11/Xpoll.h>
#include "os.h"
#include "dix.h"
#include "scrnintstr.h"
#include "vncExtInit.h"
#include "vncBlockHandler.h"
#include "xorg-version.h"
#if XORG >= 119
static void vncBlockHandler(void* data, void* timeout);
static void vncSocketNotify(int fd, int xevents, void *data);
#else
static void vncBlockHandler(void * data, OSTimePtr t, void * readmask);
static void vncWakeupHandler(void * data, int nfds, void * readmask);
struct vncFdEntry {
int fd;
int read, write;
int scrIdx;
struct vncFdEntry* next;
};
static struct vncFdEntry* fdsHead = NULL;
#endif
void vncRegisterBlockHandlers(void)
{
if (!RegisterBlockAndWakeupHandlers(vncBlockHandler,
#if XORG >= 119
(ServerWakeupHandlerProcPtr)NoopDDA,
#else
vncWakeupHandler,
#endif
0))
FatalError("RegisterBlockAndWakeupHandlers() failed\n");
}
void vncSetNotifyFd(int fd, int scrIdx, int read, int write)
{
#if XORG >= 119
int mask = (read ? X_NOTIFY_READ : 0) | (write ? X_NOTIFY_WRITE : 0);
SetNotifyFd(fd, vncSocketNotify, mask, (void*)(intptr_t)scrIdx);
#else
struct vncFdEntry* entry;
entry = fdsHead;
while (entry) {
if (entry->fd == fd) {
assert(entry->scrIdx == scrIdx);
entry->read = read;
entry->write = write;
return;
}
entry = entry->next;
}
entry = malloc(sizeof(struct vncFdEntry));
memset(entry, 0, sizeof(struct vncFdEntry));
entry->fd = fd;
entry->scrIdx = scrIdx;
entry->read = read;
entry->write = write;
entry->next = fdsHead;
fdsHead = entry;
#endif
}
void vncRemoveNotifyFd(int fd)
{
#if XORG >= 119
RemoveNotifyFd(fd);
#else
struct vncFdEntry** prev;
struct vncFdEntry* entry;
prev = &fdsHead;
entry = fdsHead;
while (entry) {
if (entry->fd == fd) {
*prev = entry->next;
return;
}
prev = &entry->next;
entry = entry->next;
}
assert(FALSE);
#endif
}
#if XORG >= 119
static void vncSocketNotify(int fd, int xevents, void *data)
{
int scrIdx;
scrIdx = (intptr_t)data;
vncHandleSocketEvent(fd, scrIdx,
xevents & X_NOTIFY_READ,
xevents & X_NOTIFY_WRITE);
}
#endif
#if XORG < 119
static void vncWriteBlockHandlerFallback(OSTimePtr timeout);
static void vncWriteWakeupHandlerFallback(void);
void vncWriteBlockHandler(fd_set *fds);
void vncWriteWakeupHandler(int nfds, fd_set *fds);
#endif
//
// vncBlockHandler - called just before the X server goes into poll().
//
// For older versions of X this also allows us to register file
// descriptors that we want read events on.
//
#if XORG >= 119
static void vncBlockHandler(void* data, void* timeout)
#else
static void vncBlockHandler(void * data, OSTimePtr t, void * readmask)
#endif
{
#if XORG < 119
int _timeout;
int* timeout = &_timeout;
static struct timeval tv;
fd_set* fds;
static struct vncFdEntry* entry;
if (*t == NULL)
_timeout = -1;
else
_timeout = (*t)->tv_sec * 1000 + (*t)->tv_usec / 1000;
#endif
vncCallBlockHandlers(timeout);
#if XORG < 119
if (_timeout != -1) {
tv.tv_sec= _timeout / 1000;
tv.tv_usec = (_timeout % 1000) * 1000;
*t = &tv;
}
fds = (fd_set*)readmask;
entry = fdsHead;
while (entry) {
if (entry->read)
FD_SET(entry->fd, fds);
entry = entry->next;
}
vncWriteBlockHandlerFallback(t);
#endif
}
#if XORG < 119
static void vncWakeupHandler(void * data, int nfds, void * readmask)
{
fd_set* fds = (fd_set*)readmask;
static struct vncFdEntry* entry;
if (nfds <= 0)
return;
entry = fdsHead;
while (entry) {
if (entry->read && FD_ISSET(entry->fd, fds))
vncHandleSocketEvent(entry->fd, entry->scrIdx, TRUE, FALSE);
entry = entry->next;
}
vncWriteWakeupHandlerFallback();
}
#endif
//
// vncWriteBlockHandler - extra hack to be able to get old versions of the X
// server to monitor writeable fds and not just readable. This requirers a
// modified Xorg and might therefore not be called.
//
#if XORG < 119
static Bool needFallback = TRUE;
static fd_set fallbackFds;
static struct timeval tw;
void vncWriteBlockHandler(fd_set *fds)
{
static struct vncFdEntry* entry;
needFallback = FALSE;
entry = fdsHead;
while (entry) {
if (entry->write)
FD_SET(entry->fd, fds);
entry = entry->next;
}
}
void vncWriteWakeupHandler(int nfds, fd_set *fds)
{
static struct vncFdEntry* entry;
if (nfds <= 0)
return;
entry = fdsHead;
while (entry) {
if (entry->write && FD_ISSET(entry->fd, fds))
vncHandleSocketEvent(entry->fd, entry->scrIdx, FALSE, TRUE);
entry = entry->next;
}
}
static void vncWriteBlockHandlerFallback(OSTimePtr timeout)
{
if (!needFallback)
return;
FD_ZERO(&fallbackFds);
vncWriteBlockHandler(&fallbackFds);
// vncWriteBlockHandler() will clear this, so we need to restore it
needFallback = TRUE;
if (!XFD_ANYSET(&fallbackFds))
return;
if ((*timeout == NULL) ||
((*timeout)->tv_sec > 0) || ((*timeout)->tv_usec > 10000)) {
tw.tv_sec = 0;
tw.tv_usec = 10000;
*timeout = &tw;
}
}
static void vncWriteWakeupHandlerFallback(void)
{
int ret;
struct timeval timeout;
if (!needFallback)
return;
if (!XFD_ANYSET(&fallbackFds))
return;
timeout.tv_sec = 0;
timeout.tv_usec = 0;
ret = select(XFD_SETSIZE, NULL, &fallbackFds, NULL, &timeout);
if (ret < 0) {
ErrorF("vncWriteWakeupHandlerFallback(): select: %s\n",
strerror(errno));
return;
}
if (ret == 0)
return;
vncWriteWakeupHandler(ret, &fallbackFds);
}
#endif