1 /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 * Copyright 2011-2014 Pierre Ossman for Cendio AB
3 *
4 * This is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This software is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this software; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 * USA.
18 */
19
20 #ifdef HAVE_DIX_CONFIG_H
21 #include <dix-config.h>
22 #endif
23
24 #include <errno.h>
25
26 #include <X11/Xpoll.h>
27
28 #include "os.h"
29 #include "dix.h"
30 #include "scrnintstr.h"
31
32 #include "vncExtInit.h"
33 #include "vncBlockHandler.h"
34 #include "xorg-version.h"
35
36 #if XORG_AT_LEAST(1, 19, 0)
37 static void vncBlockHandler(void* data, void* timeout);
38 static void vncSocketNotify(int fd, int xevents, void *data);
39 #else
40 static void vncBlockHandler(void * data, OSTimePtr t, void * readmask);
41 static void vncWakeupHandler(void * data, int nfds, void * readmask);
42
43 struct vncFdEntry {
44 int fd;
45 int read, write;
46 int scrIdx;
47 struct vncFdEntry* next;
48 };
49
50 static struct vncFdEntry* fdsHead = NULL;
51 #endif
52
vncRegisterBlockHandlers(void)53 void vncRegisterBlockHandlers(void)
54 {
55 if (!RegisterBlockAndWakeupHandlers(vncBlockHandler,
56 #if XORG_AT_LEAST(1, 19, 0)
57 (ServerWakeupHandlerProcPtr)NoopDDA,
58 #else
59 vncWakeupHandler,
60 #endif
61 0))
62 FatalError("RegisterBlockAndWakeupHandlers() failed\n");
63 }
64
vncSetNotifyFd(int fd,int scrIdx,int read,int write)65 void vncSetNotifyFd(int fd, int scrIdx, int read, int write)
66 {
67 #if XORG_AT_LEAST(1, 19, 0)
68 int mask = (read ? X_NOTIFY_READ : 0) | (write ? X_NOTIFY_WRITE : 0);
69 SetNotifyFd(fd, vncSocketNotify, mask, (void*)(intptr_t)scrIdx);
70 #else
71 struct vncFdEntry* entry;
72
73 entry = fdsHead;
74 while (entry) {
75 if (entry->fd == fd) {
76 assert(entry->scrIdx == scrIdx);
77 entry->read = read;
78 entry->write = write;
79 return;
80 }
81 entry = entry->next;
82 }
83
84 entry = malloc(sizeof(struct vncFdEntry));
85 memset(entry, 0, sizeof(struct vncFdEntry));
86
87 entry->fd = fd;
88 entry->scrIdx = scrIdx;
89 entry->read = read;
90 entry->write = write;
91
92 entry->next = fdsHead;
93 fdsHead = entry;
94 #endif
95 }
96
vncRemoveNotifyFd(int fd)97 void vncRemoveNotifyFd(int fd)
98 {
99 #if XORG_AT_LEAST(1, 19, 0)
100 RemoveNotifyFd(fd);
101 #else
102 struct vncFdEntry** prev;
103 struct vncFdEntry* entry;
104
105 prev = &fdsHead;
106 entry = fdsHead;
107 while (entry) {
108 if (entry->fd == fd) {
109 *prev = entry->next;
110 return;
111 }
112 prev = &entry->next;
113 entry = entry->next;
114 }
115
116 assert(FALSE);
117 #endif
118 }
119
120 #if XORG_AT_LEAST(1, 19, 0)
vncSocketNotify(int fd,int xevents,void * data)121 static void vncSocketNotify(int fd, int xevents, void *data)
122 {
123 int scrIdx;
124
125 scrIdx = (intptr_t)data;
126 vncHandleSocketEvent(fd, scrIdx,
127 xevents & X_NOTIFY_READ,
128 xevents & X_NOTIFY_WRITE);
129 }
130 #endif
131
132 #if XORG_OLDER_THAN(1, 19, 0)
133 static void vncWriteBlockHandlerFallback(OSTimePtr timeout);
134 static void vncWriteWakeupHandlerFallback(void);
135 void vncWriteBlockHandler(fd_set *fds);
136 void vncWriteWakeupHandler(int nfds, fd_set *fds);
137 #endif
138
139 //
140 // vncBlockHandler - called just before the X server goes into poll().
141 //
142 // For older versions of X this also allows us to register file
143 // descriptors that we want read events on.
144 //
145
146 #if XORG_AT_LEAST(1, 19, 0)
vncBlockHandler(void * data,void * timeout)147 static void vncBlockHandler(void* data, void* timeout)
148 #else
149 static void vncBlockHandler(void * data, OSTimePtr t, void * readmask)
150 #endif
151 {
152 #if XORG_OLDER_THAN(1, 19, 0)
153 int _timeout;
154 int* timeout = &_timeout;
155 static struct timeval tv;
156
157 fd_set* fds;
158 static struct vncFdEntry* entry;
159
160 if (*t == NULL)
161 _timeout = -1;
162 else
163 _timeout = (*t)->tv_sec * 1000 + (*t)->tv_usec / 1000;
164 #endif
165
166 vncCallBlockHandlers(timeout);
167
168 #if XORG_OLDER_THAN(1, 19, 0)
169 if (_timeout != -1) {
170 tv.tv_sec= _timeout / 1000;
171 tv.tv_usec = (_timeout % 1000) * 1000;
172 *t = &tv;
173 }
174
175 fds = (fd_set*)readmask;
176 entry = fdsHead;
177 while (entry) {
178 if (entry->read)
179 FD_SET(entry->fd, fds);
180 entry = entry->next;
181 }
182
183 vncWriteBlockHandlerFallback(t);
184 #endif
185 }
186
187 #if XORG_OLDER_THAN(1, 19, 0)
vncWakeupHandler(void * data,int nfds,void * readmask)188 static void vncWakeupHandler(void * data, int nfds, void * readmask)
189 {
190 fd_set* fds = (fd_set*)readmask;
191
192 static struct vncFdEntry* entry;
193
194 if (nfds <= 0)
195 return;
196
197 entry = fdsHead;
198 while (entry) {
199 if (entry->read && FD_ISSET(entry->fd, fds))
200 vncHandleSocketEvent(entry->fd, entry->scrIdx, TRUE, FALSE);
201 entry = entry->next;
202 }
203
204 vncWriteWakeupHandlerFallback();
205 }
206 #endif
207
208 //
209 // vncWriteBlockHandler - extra hack to be able to get old versions of the X
210 // server to monitor writeable fds and not just readable. This requirers a
211 // modified Xorg and might therefore not be called.
212 //
213
214 #if XORG_OLDER_THAN(1, 19, 0)
215 static Bool needFallback = TRUE;
216 static fd_set fallbackFds;
217 static struct timeval tw;
218
vncWriteBlockHandler(fd_set * fds)219 void vncWriteBlockHandler(fd_set *fds)
220 {
221 static struct vncFdEntry* entry;
222
223 needFallback = FALSE;
224
225 entry = fdsHead;
226 while (entry) {
227 if (entry->write)
228 FD_SET(entry->fd, fds);
229 entry = entry->next;
230 }
231 }
232
vncWriteWakeupHandler(int nfds,fd_set * fds)233 void vncWriteWakeupHandler(int nfds, fd_set *fds)
234 {
235 static struct vncFdEntry* entry;
236
237 if (nfds <= 0)
238 return;
239
240 entry = fdsHead;
241 while (entry) {
242 if (entry->write && FD_ISSET(entry->fd, fds))
243 vncHandleSocketEvent(entry->fd, entry->scrIdx, FALSE, TRUE);
244 entry = entry->next;
245 }
246 }
247
vncWriteBlockHandlerFallback(OSTimePtr timeout)248 static void vncWriteBlockHandlerFallback(OSTimePtr timeout)
249 {
250 if (!needFallback)
251 return;
252
253 FD_ZERO(&fallbackFds);
254 vncWriteBlockHandler(&fallbackFds);
255
256 // vncWriteBlockHandler() will clear this, so we need to restore it
257 needFallback = TRUE;
258
259 if (!XFD_ANYSET(&fallbackFds))
260 return;
261
262 if ((*timeout == NULL) ||
263 ((*timeout)->tv_sec > 0) || ((*timeout)->tv_usec > 10000)) {
264 tw.tv_sec = 0;
265 tw.tv_usec = 10000;
266 *timeout = &tw;
267 }
268 }
269
vncWriteWakeupHandlerFallback(void)270 static void vncWriteWakeupHandlerFallback(void)
271 {
272 int ret;
273 struct timeval timeout;
274
275 if (!needFallback)
276 return;
277
278 if (!XFD_ANYSET(&fallbackFds))
279 return;
280
281 timeout.tv_sec = 0;
282 timeout.tv_usec = 0;
283
284 ret = select(XFD_SETSIZE, NULL, &fallbackFds, NULL, &timeout);
285 if (ret < 0) {
286 ErrorF("vncWriteWakeupHandlerFallback(): select: %s\n",
287 strerror(errno));
288 return;
289 }
290
291 if (ret == 0)
292 return;
293
294 vncWriteWakeupHandler(ret, &fallbackFds);
295 }
296 #endif
297