You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

vncBlockHandler.c 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  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. #ifdef HAVE_DIX_CONFIG_H
  20. #include <dix-config.h>
  21. #endif
  22. #include <errno.h>
  23. #include <X11/Xpoll.h>
  24. #include "os.h"
  25. #include "dix.h"
  26. #include "scrnintstr.h"
  27. #include "vncExtInit.h"
  28. #include "vncBlockHandler.h"
  29. #include "xorg-version.h"
  30. #if XORG >= 119
  31. static void vncBlockHandler(void* data, void* timeout);
  32. static void vncSocketNotify(int fd, int xevents, void *data);
  33. #else
  34. static void vncBlockHandler(void * data, OSTimePtr t, void * readmask);
  35. static void vncWakeupHandler(void * data, int nfds, void * readmask);
  36. struct vncFdEntry {
  37. int fd;
  38. int read, write;
  39. int scrIdx;
  40. struct vncFdEntry* next;
  41. };
  42. static struct vncFdEntry* fdsHead = NULL;
  43. #endif
  44. void vncRegisterBlockHandlers(void)
  45. {
  46. if (!RegisterBlockAndWakeupHandlers(vncBlockHandler,
  47. #if XORG >= 119
  48. (ServerWakeupHandlerProcPtr)NoopDDA,
  49. #else
  50. vncWakeupHandler,
  51. #endif
  52. 0))
  53. FatalError("RegisterBlockAndWakeupHandlers() failed\n");
  54. }
  55. void vncSetNotifyFd(int fd, int scrIdx, int read, int write)
  56. {
  57. #if XORG >= 119
  58. int mask = (read ? X_NOTIFY_READ : 0) | (write ? X_NOTIFY_WRITE : 0);
  59. SetNotifyFd(fd, vncSocketNotify, mask, (void*)(intptr_t)scrIdx);
  60. #else
  61. struct vncFdEntry* entry;
  62. entry = fdsHead;
  63. while (entry) {
  64. if (entry->fd == fd) {
  65. assert(entry->scrIdx == scrIdx);
  66. entry->read = read;
  67. entry->write = write;
  68. return;
  69. }
  70. entry = entry->next;
  71. }
  72. entry = malloc(sizeof(struct vncFdEntry));
  73. memset(entry, 0, sizeof(struct vncFdEntry));
  74. entry->fd = fd;
  75. entry->scrIdx = scrIdx;
  76. entry->read = read;
  77. entry->write = write;
  78. entry->next = fdsHead;
  79. fdsHead = entry;
  80. #endif
  81. }
  82. void vncRemoveNotifyFd(int fd)
  83. {
  84. #if XORG >= 119
  85. RemoveNotifyFd(fd);
  86. #else
  87. struct vncFdEntry** prev;
  88. struct vncFdEntry* entry;
  89. prev = &fdsHead;
  90. entry = fdsHead;
  91. while (entry) {
  92. if (entry->fd == fd) {
  93. *prev = entry->next;
  94. return;
  95. }
  96. prev = &entry->next;
  97. entry = entry->next;
  98. }
  99. assert(FALSE);
  100. #endif
  101. }
  102. #if XORG >= 119
  103. static void vncSocketNotify(int fd, int xevents, void *data)
  104. {
  105. int scrIdx;
  106. scrIdx = (intptr_t)data;
  107. vncHandleSocketEvent(fd, scrIdx,
  108. xevents & X_NOTIFY_READ,
  109. xevents & X_NOTIFY_WRITE);
  110. }
  111. #endif
  112. #if XORG < 119
  113. static void vncWriteBlockHandlerFallback(OSTimePtr timeout);
  114. static void vncWriteWakeupHandlerFallback(void);
  115. void vncWriteBlockHandler(fd_set *fds);
  116. void vncWriteWakeupHandler(int nfds, fd_set *fds);
  117. #endif
  118. //
  119. // vncBlockHandler - called just before the X server goes into poll().
  120. //
  121. // For older versions of X this also allows us to register file
  122. // descriptors that we want read events on.
  123. //
  124. #if XORG >= 119
  125. static void vncBlockHandler(void* data, void* timeout)
  126. #else
  127. static void vncBlockHandler(void * data, OSTimePtr t, void * readmask)
  128. #endif
  129. {
  130. #if XORG < 119
  131. int _timeout;
  132. int* timeout = &_timeout;
  133. static struct timeval tv;
  134. fd_set* fds;
  135. static struct vncFdEntry* entry;
  136. if (*t == NULL)
  137. _timeout = -1;
  138. else
  139. _timeout = (*t)->tv_sec * 1000 + (*t)->tv_usec / 1000;
  140. #endif
  141. vncCallBlockHandlers(timeout);
  142. #if XORG < 119
  143. if (_timeout != -1) {
  144. tv.tv_sec= _timeout / 1000;
  145. tv.tv_usec = (_timeout % 1000) * 1000;
  146. *t = &tv;
  147. }
  148. fds = (fd_set*)readmask;
  149. entry = fdsHead;
  150. while (entry) {
  151. if (entry->read)
  152. FD_SET(entry->fd, fds);
  153. entry = entry->next;
  154. }
  155. vncWriteBlockHandlerFallback(t);
  156. #endif
  157. }
  158. #if XORG < 119
  159. static void vncWakeupHandler(void * data, int nfds, void * readmask)
  160. {
  161. fd_set* fds = (fd_set*)readmask;
  162. static struct vncFdEntry* entry;
  163. if (nfds <= 0)
  164. return;
  165. entry = fdsHead;
  166. while (entry) {
  167. if (entry->read && FD_ISSET(entry->fd, fds))
  168. vncHandleSocketEvent(entry->fd, entry->scrIdx, TRUE, FALSE);
  169. entry = entry->next;
  170. }
  171. vncWriteWakeupHandlerFallback();
  172. }
  173. #endif
  174. //
  175. // vncWriteBlockHandler - extra hack to be able to get old versions of the X
  176. // server to monitor writeable fds and not just readable. This requirers a
  177. // modified Xorg and might therefore not be called.
  178. //
  179. #if XORG < 119
  180. static Bool needFallback = TRUE;
  181. static fd_set fallbackFds;
  182. static struct timeval tw;
  183. void vncWriteBlockHandler(fd_set *fds)
  184. {
  185. static struct vncFdEntry* entry;
  186. needFallback = FALSE;
  187. entry = fdsHead;
  188. while (entry) {
  189. if (entry->write)
  190. FD_SET(entry->fd, fds);
  191. entry = entry->next;
  192. }
  193. }
  194. void vncWriteWakeupHandler(int nfds, fd_set *fds)
  195. {
  196. static struct vncFdEntry* entry;
  197. if (nfds <= 0)
  198. return;
  199. entry = fdsHead;
  200. while (entry) {
  201. if (entry->write && FD_ISSET(entry->fd, fds))
  202. vncHandleSocketEvent(entry->fd, entry->scrIdx, FALSE, TRUE);
  203. entry = entry->next;
  204. }
  205. }
  206. static void vncWriteBlockHandlerFallback(OSTimePtr timeout)
  207. {
  208. if (!needFallback)
  209. return;
  210. FD_ZERO(&fallbackFds);
  211. vncWriteBlockHandler(&fallbackFds);
  212. // vncWriteBlockHandler() will clear this, so we need to restore it
  213. needFallback = TRUE;
  214. if (!XFD_ANYSET(&fallbackFds))
  215. return;
  216. if ((*timeout == NULL) ||
  217. ((*timeout)->tv_sec > 0) || ((*timeout)->tv_usec > 10000)) {
  218. tw.tv_sec = 0;
  219. tw.tv_usec = 10000;
  220. *timeout = &tw;
  221. }
  222. }
  223. static void vncWriteWakeupHandlerFallback(void)
  224. {
  225. int ret;
  226. struct timeval timeout;
  227. if (!needFallback)
  228. return;
  229. if (!XFD_ANYSET(&fallbackFds))
  230. return;
  231. timeout.tv_sec = 0;
  232. timeout.tv_usec = 0;
  233. ret = select(XFD_SETSIZE, NULL, &fallbackFds, NULL, &timeout);
  234. if (ret < 0) {
  235. ErrorF("vncWriteWakeupHandlerFallback(): select: %s\n",
  236. strerror(errno));
  237. return;
  238. }
  239. if (ret == 0)
  240. return;
  241. vncWriteWakeupHandler(ret, &fallbackFds);
  242. }
  243. #endif