/src/libvncserver/src/libvncserver/rfbserver.c
Line | Count | Source |
1 | | /* |
2 | | * rfbserver.c - deal with server-side of the RFB protocol. |
3 | | */ |
4 | | |
5 | | /* |
6 | | * Copyright (C) 2011-2012 D. R. Commander |
7 | | * Copyright (C) 2005 Rohit Kumar, Johannes E. Schindelin |
8 | | * Copyright (C) 2002 RealVNC Ltd. |
9 | | * OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>. |
10 | | * Original Xvnc code Copyright (C) 1999 AT&T Laboratories Cambridge. |
11 | | * All Rights Reserved. |
12 | | * |
13 | | * This is free software; you can redistribute it and/or modify |
14 | | * it under the terms of the GNU General Public License as published by |
15 | | * the Free Software Foundation; either version 2 of the License, or |
16 | | * (at your option) any later version. |
17 | | * |
18 | | * This software is distributed in the hope that it will be useful, |
19 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
21 | | * GNU General Public License for more details. |
22 | | * |
23 | | * You should have received a copy of the GNU General Public License |
24 | | * along with this software; if not, write to the Free Software |
25 | | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
26 | | * USA. |
27 | | */ |
28 | | |
29 | | #ifdef __STRICT_ANSI__ |
30 | | #define _BSD_SOURCE |
31 | | #define _POSIX_SOURCE |
32 | | #define _XOPEN_SOURCE 600 |
33 | | #endif |
34 | | |
35 | | #include <stdio.h> |
36 | | #include <string.h> |
37 | | #include <rfb/rfb.h> |
38 | | #include <rfb/rfbregion.h> |
39 | | #include "private.h" |
40 | | #include "rfb/rfbconfig.h" |
41 | | |
42 | | #ifdef LIBVNCSERVER_HAVE_FCNTL_H |
43 | | #include <fcntl.h> |
44 | | #endif |
45 | | |
46 | | #ifdef WIN32 |
47 | | #include <io.h> |
48 | | #else |
49 | | #include <pwd.h> |
50 | | #endif |
51 | | |
52 | | #include "sockets.h" |
53 | | |
54 | | #ifdef DEBUGPROTO |
55 | | #undef DEBUGPROTO |
56 | | #define DEBUGPROTO(x) x |
57 | | #else |
58 | | #define DEBUGPROTO(x) |
59 | | #endif |
60 | | #include <stdarg.h> |
61 | | #include "scale.h" |
62 | | /* stst() */ |
63 | | #include <sys/types.h> |
64 | | #include <sys/stat.h> |
65 | | #if LIBVNCSERVER_HAVE_UNISTD_H |
66 | | #include <unistd.h> |
67 | | #endif |
68 | | |
69 | | #ifndef WIN32 |
70 | | /* readdir() */ |
71 | | #include <dirent.h> |
72 | | #endif |
73 | | |
74 | | /* errno */ |
75 | | #include <errno.h> |
76 | | /* strftime() */ |
77 | | #include <time.h> |
78 | | /* INT_MAX */ |
79 | | #include <limits.h> |
80 | | |
81 | | #ifdef LIBVNCSERVER_WITH_WEBSOCKETS |
82 | | #include "rfbssl.h" |
83 | | #endif |
84 | | |
85 | | #ifdef _MSC_VER |
86 | | /* Prevent POSIX deprecation warnings */ |
87 | | #define close _close |
88 | | #define strdup _strdup |
89 | | #endif |
90 | | |
91 | | #ifdef WIN32 |
92 | | #include <direct.h> |
93 | | #ifdef __MINGW32__ |
94 | | #define mkdir(path, perms) mkdir(path) /* Omit the perms argument to match POSIX signature */ |
95 | | #else /* MSVC and other windows compilers */ |
96 | | #define mkdir(path, perms) _mkdir(path) /* Omit the perms argument to match POSIX signature */ |
97 | | #endif /* __MINGW32__ else... */ |
98 | | #ifndef S_ISDIR |
99 | | #define S_ISDIR(m) (((m) & S_IFDIR) == S_IFDIR) |
100 | | #endif |
101 | | #endif |
102 | | |
103 | | #ifdef LIBVNCSERVER_HAVE_LIBJPEG |
104 | | /* |
105 | | * Map of quality levels to provide compatibility with TightVNC/TigerVNC |
106 | | * clients. This emulates the behavior of the TigerVNC Server. |
107 | | */ |
108 | | |
109 | | static const int tight2turbo_qual[10] = { |
110 | | 15, 29, 41, 42, 62, 77, 79, 86, 92, 100 |
111 | | }; |
112 | | |
113 | | static const int tight2turbo_subsamp[10] = { |
114 | | 1, 1, 1, 2, 2, 2, 0, 0, 0, 0 |
115 | | }; |
116 | | #endif |
117 | | |
118 | | static void rfbProcessClientProtocolVersion(rfbClientPtr cl); |
119 | | static void rfbProcessClientNormalMessage(rfbClientPtr cl); |
120 | | static void rfbProcessClientInitMessage(rfbClientPtr cl); |
121 | | |
122 | | #if defined(LIBVNCSERVER_HAVE_LIBPTHREAD) || defined(LIBVNCSERVER_HAVE_WIN32THREADS) |
123 | | void rfbIncrClientRef(rfbClientPtr cl) |
124 | 0 | { |
125 | 0 | LOCK(cl->refCountMutex); |
126 | 0 | cl->refCount++; |
127 | 0 | UNLOCK(cl->refCountMutex); |
128 | 0 | } |
129 | | |
130 | | void rfbDecrClientRef(rfbClientPtr cl) |
131 | 0 | { |
132 | 0 | LOCK(cl->refCountMutex); |
133 | 0 | cl->refCount--; |
134 | 0 | if(cl->refCount<=0) /* just to be sure also < 0 */ |
135 | 0 | TSIGNAL(cl->deleteCond); |
136 | 0 | UNLOCK(cl->refCountMutex); |
137 | 0 | } |
138 | | #else |
139 | | void rfbIncrClientRef(rfbClientPtr cl) {} |
140 | | void rfbDecrClientRef(rfbClientPtr cl) {} |
141 | | #endif |
142 | | |
143 | | #if defined(LIBVNCSERVER_HAVE_LIBPTHREAD) || defined(LIBVNCSERVER_HAVE_WIN32THREADS) |
144 | | static MUTEX(rfbClientListMutex); |
145 | | #endif |
146 | | |
147 | | struct rfbClientIterator { |
148 | | rfbClientPtr next; |
149 | | rfbScreenInfoPtr screen; |
150 | | rfbBool closedToo; |
151 | | }; |
152 | | |
153 | | void |
154 | | rfbClientListInit(rfbScreenInfoPtr rfbScreen) |
155 | 1 | { |
156 | 1 | if(sizeof(rfbBool)!=1) { |
157 | | /* a sanity check */ |
158 | 0 | fprintf(stderr,"rfbBool's size is not 1 (%d)!\n",(int)sizeof(rfbBool)); |
159 | | /* we cannot continue, because rfbBool is supposed to be char everywhere */ |
160 | 0 | exit(1); |
161 | 0 | } |
162 | 1 | rfbScreen->clientHead = NULL; |
163 | 1 | INIT_MUTEX(rfbClientListMutex); |
164 | 1 | } |
165 | | |
166 | | rfbClientIteratorPtr |
167 | | rfbGetClientIterator(rfbScreenInfoPtr rfbScreen) |
168 | 10.4k | { |
169 | 10.4k | rfbClientIteratorPtr i = |
170 | 10.4k | (rfbClientIteratorPtr)malloc(sizeof(struct rfbClientIterator)); |
171 | 10.4k | if(i) { |
172 | 10.4k | i->next = NULL; |
173 | 10.4k | i->screen = rfbScreen; |
174 | 10.4k | i->closedToo = FALSE; |
175 | 10.4k | } |
176 | 10.4k | return i; |
177 | 10.4k | } |
178 | | |
179 | | rfbClientIteratorPtr |
180 | | rfbGetClientIteratorWithClosed(rfbScreenInfoPtr rfbScreen) |
181 | 0 | { |
182 | 0 | rfbClientIteratorPtr i = |
183 | 0 | (rfbClientIteratorPtr)malloc(sizeof(struct rfbClientIterator)); |
184 | 0 | if(i) { |
185 | 0 | i->next = NULL; |
186 | 0 | i->screen = rfbScreen; |
187 | 0 | i->closedToo = TRUE; |
188 | 0 | } |
189 | 0 | return i; |
190 | 0 | } |
191 | | |
192 | | rfbClientPtr |
193 | | rfbClientIteratorHead(rfbClientIteratorPtr i) |
194 | 0 | { |
195 | 0 | #if defined(LIBVNCSERVER_HAVE_LIBPTHREAD) || defined(LIBVNCSERVER_HAVE_WIN32THREADS) |
196 | 0 | if(i->next != 0) { |
197 | 0 | rfbDecrClientRef(i->next); |
198 | 0 | rfbIncrClientRef(i->screen->clientHead); |
199 | 0 | } |
200 | 0 | #endif |
201 | 0 | LOCK(rfbClientListMutex); |
202 | 0 | i->next = i->screen->clientHead; |
203 | 0 | UNLOCK(rfbClientListMutex); |
204 | 0 | return i->next; |
205 | 0 | } |
206 | | |
207 | | rfbClientPtr |
208 | | rfbClientIteratorNext(rfbClientIteratorPtr i) |
209 | 10.4k | { |
210 | 10.4k | if (!i) |
211 | 0 | return NULL; |
212 | 10.4k | if(i->next == 0) { |
213 | 10.4k | LOCK(rfbClientListMutex); |
214 | 10.4k | i->next = i->screen->clientHead; |
215 | 10.4k | UNLOCK(rfbClientListMutex); |
216 | 10.4k | } else { |
217 | 0 | rfbClientPtr cl = i->next; |
218 | 0 | i->next = i->next->next; |
219 | 0 | rfbDecrClientRef(cl); |
220 | 0 | } |
221 | | |
222 | 10.4k | #if defined(LIBVNCSERVER_HAVE_LIBPTHREAD) || defined(LIBVNCSERVER_HAVE_WIN32THREADS) |
223 | 10.4k | if(!i->closedToo) |
224 | 18.4k | while(i->next && i->next->sock<0) |
225 | 8.05k | i->next = i->next->next; |
226 | 10.4k | if(i->next) |
227 | 0 | rfbIncrClientRef(i->next); |
228 | 10.4k | #endif |
229 | | |
230 | 10.4k | return i->next; |
231 | 10.4k | } |
232 | | |
233 | | void |
234 | | rfbReleaseClientIterator(rfbClientIteratorPtr iterator) |
235 | 10.4k | { |
236 | 10.4k | if(iterator && iterator->next) rfbDecrClientRef(iterator->next); |
237 | 10.4k | free(iterator); |
238 | 10.4k | } |
239 | | |
240 | | |
241 | | /* |
242 | | * rfbNewClientConnection is called from sockets.c when a new connection |
243 | | * comes in. |
244 | | */ |
245 | | |
246 | | void |
247 | | rfbNewClientConnection(rfbScreenInfoPtr rfbScreen, |
248 | | rfbSocket sock) |
249 | 0 | { |
250 | 0 | rfbNewClient(rfbScreen,sock); |
251 | 0 | } |
252 | | |
253 | | |
254 | | /* |
255 | | * rfbReverseConnection is called to make an outward |
256 | | * connection to a "listening" RFB client. |
257 | | */ |
258 | | |
259 | | rfbClientPtr |
260 | | rfbReverseConnection(rfbScreenInfoPtr rfbScreen, |
261 | | char *host, |
262 | | int port) |
263 | 0 | { |
264 | 0 | rfbSocket sock; |
265 | 0 | rfbClientPtr cl; |
266 | |
|
267 | 0 | if ((sock = rfbConnect(rfbScreen, host, port)) < 0) |
268 | 0 | return (rfbClientPtr)NULL; |
269 | | |
270 | 0 | cl = rfbNewClient(rfbScreen, sock); |
271 | |
|
272 | 0 | if (cl) { |
273 | 0 | cl->reverseConnection = TRUE; |
274 | 0 | cl->destPort = port; |
275 | 0 | if (!cl->onHold) |
276 | 0 | rfbStartOnHoldClient(cl); |
277 | 0 | } |
278 | |
|
279 | 0 | return cl; |
280 | 0 | } |
281 | | |
282 | | |
283 | | rfbClientPtr rfbUltraVNCRepeaterMode2Connection(rfbScreenInfoPtr rfbScreen, |
284 | | char *repeaterHost, |
285 | | int repeaterPort, |
286 | | const char* repeaterId) |
287 | 0 | { |
288 | 0 | rfbSocket sock; |
289 | 0 | rfbClientPtr cl; |
290 | | // Using 250 here as this is what UltraVNC repeaters expect to read in one |
291 | | // go. If we send less bytes as an id, the repeater will read our |
292 | | // rfbProtocolVersion message into its id buffer, thus rfbProtocolVersion |
293 | | // will never reach the viewer. |
294 | 0 | char id[250]; |
295 | 0 | rfbLog("rfbUltraVNCRepeaterMode2Connection: connecting to repeater %s:%d\n", repeaterHost, repeaterPort); |
296 | |
|
297 | 0 | if ((sock = rfbConnect(rfbScreen, repeaterHost, repeaterPort)) == RFB_INVALID_SOCKET) { |
298 | 0 | return NULL; |
299 | 0 | } |
300 | | |
301 | 0 | memset(id, 0, sizeof(id)); |
302 | 0 | if (snprintf(id, sizeof(id), "ID:%s", repeaterId) >= (int)sizeof(id)) { |
303 | | /* truncated! */ |
304 | 0 | rfbErr("rfbUltraVNCRepeaterMode2Connection: error, given ID is too long.\n"); |
305 | 0 | return NULL; |
306 | 0 | } |
307 | | |
308 | 0 | if (send(sock, id, sizeof(id), 0) != sizeof(id)) { |
309 | 0 | rfbErr("rfbUltraVNCRepeaterMode2Connection: sending repeater ID failed\n"); |
310 | 0 | return NULL; |
311 | 0 | } |
312 | | |
313 | 0 | cl = rfbNewClient(rfbScreen, sock); |
314 | 0 | if (!cl) { |
315 | 0 | rfbErr("rfbUltraVNCRepeaterMode2Connection: new client failed\n"); |
316 | 0 | return NULL; |
317 | 0 | } |
318 | | |
319 | 0 | cl->reverseConnection = 0; |
320 | 0 | cl->destPort = repeaterPort; |
321 | | |
322 | | // Save repeater id without the 'ID:' prefix |
323 | 0 | cl->repeaterId = malloc(sizeof(id) - 3); |
324 | 0 | if(cl->repeaterId) { |
325 | 0 | memcpy(cl->repeaterId, id + 3, sizeof(id) - 3); |
326 | 0 | } else { |
327 | 0 | rfbErr("rfbUltraVNCRepeaterMode2Connection: could not allocate memory for saving repeater id\n"); |
328 | 0 | } |
329 | |
|
330 | 0 | if (!cl->onHold) { |
331 | 0 | rfbStartOnHoldClient(cl); |
332 | 0 | } |
333 | |
|
334 | 0 | return cl; |
335 | 0 | } |
336 | | |
337 | | |
338 | | void |
339 | | rfbSetProtocolVersion(rfbScreenInfoPtr rfbScreen, int major_, int minor_) |
340 | 0 | { |
341 | | /* Permit the server to set the version to report */ |
342 | | /* TODO: sanity checking */ |
343 | 0 | if ((major_==3) && (minor_ > 2 && minor_ < 9)) |
344 | 0 | { |
345 | 0 | rfbScreen->protocolMajorVersion = major_; |
346 | 0 | rfbScreen->protocolMinorVersion = minor_; |
347 | 0 | } |
348 | 0 | else |
349 | 0 | rfbLog("rfbSetProtocolVersion(%d,%d) set to invalid values\n", major_, minor_); |
350 | 0 | } |
351 | | |
352 | | /* |
353 | | * rfbNewClient is called when a new connection has been made by whatever |
354 | | * means. |
355 | | */ |
356 | | |
357 | | static rfbClientPtr |
358 | | rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen, |
359 | | rfbSocket sock, |
360 | | rfbBool isUDP) |
361 | 2.38k | { |
362 | 2.38k | rfbProtocolVersionMsg pv; |
363 | 2.38k | rfbClientIteratorPtr iterator; |
364 | 2.38k | rfbClientPtr cl,cl_; |
365 | 2.38k | #ifdef LIBVNCSERVER_IPv6 |
366 | 2.38k | struct sockaddr_storage addr; |
367 | | #else |
368 | | struct sockaddr_in addr; |
369 | | #endif |
370 | 2.38k | socklen_t addrlen = sizeof(addr); |
371 | 2.38k | rfbProtocolExtension* extension; |
372 | | |
373 | 2.38k | cl = (rfbClientPtr)calloc(sizeof(rfbClientRec),1); |
374 | | |
375 | 2.38k | if (!cl) |
376 | 0 | return NULL; |
377 | | |
378 | 2.38k | cl->screen = rfbScreen; |
379 | 2.38k | cl->sock = sock; |
380 | 2.38k | cl->viewOnly = FALSE; |
381 | | /* setup pseudo scaling */ |
382 | 2.38k | cl->scaledScreen = rfbScreen; |
383 | 2.38k | cl->scaledScreen->scaledScreenRefCount++; |
384 | | |
385 | 2.38k | rfbResetStats(cl); |
386 | | |
387 | 2.38k | cl->clientData = NULL; |
388 | 2.38k | cl->clientGoneHook = rfbDoNothingWithClient; |
389 | | |
390 | 2.38k | if(isUDP) { |
391 | 0 | rfbLog(" accepted UDP client\n"); |
392 | 2.38k | } else { |
393 | 2.38k | #ifdef LIBVNCSERVER_IPv6 |
394 | 2.38k | char host[1024]; |
395 | 2.38k | #endif |
396 | 2.38k | int one=1; |
397 | 2.38k | size_t otherClientsCount = 0; |
398 | | |
399 | 2.38k | getpeername(sock, (struct sockaddr *)&addr, &addrlen); |
400 | 2.38k | #ifdef LIBVNCSERVER_IPv6 |
401 | 2.38k | if(getnameinfo((struct sockaddr*)&addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST) != 0) { |
402 | 2.38k | rfbLogPerror("rfbNewClient: error in getnameinfo"); |
403 | 2.38k | cl->host = strdup(""); |
404 | 2.38k | } |
405 | 0 | else |
406 | 0 | cl->host = strdup(host); |
407 | | #else |
408 | | cl->host = strdup(inet_ntoa(addr.sin_addr)); |
409 | | #endif |
410 | | |
411 | 2.38k | cl->destPort = -1; |
412 | | |
413 | 2.38k | iterator = rfbGetClientIterator(rfbScreen); |
414 | 2.38k | while ((cl_ = rfbClientIteratorNext(iterator)) != NULL) |
415 | 0 | ++otherClientsCount; |
416 | 2.38k | rfbReleaseClientIterator(iterator); |
417 | 2.38k | rfbLog(" %lu other clients\n", (unsigned long) otherClientsCount); |
418 | | |
419 | | #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
420 | | if(!rfbSetNonBlocking(sock)) { |
421 | | rfbCloseSocket(sock); |
422 | | return NULL; |
423 | | } |
424 | | |
425 | | if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, |
426 | | (char *)&one, sizeof(one)) < 0) { |
427 | | rfbLogPerror("setsockopt failed: can't set TCP_NODELAY flag, non TCP socket?"); |
428 | | } |
429 | | |
430 | | FD_SET(sock,&(rfbScreen->allFds)); |
431 | | rfbScreen->maxFd = rfbMax(sock,rfbScreen->maxFd); |
432 | | #endif |
433 | | |
434 | 2.38k | INIT_MUTEX(cl->outputMutex); |
435 | 2.38k | INIT_MUTEX(cl->refCountMutex); |
436 | 2.38k | INIT_MUTEX(cl->sendMutex); |
437 | 2.38k | INIT_COND(cl->deleteCond); |
438 | | |
439 | 2.38k | cl->state = RFB_PROTOCOL_VERSION; |
440 | | |
441 | 2.38k | cl->reverseConnection = FALSE; |
442 | 2.38k | cl->readyForSetColourMapEntries = FALSE; |
443 | 2.38k | cl->useCopyRect = FALSE; |
444 | 2.38k | cl->preferredEncoding = -1; |
445 | 2.38k | cl->correMaxWidth = 48; |
446 | 2.38k | cl->correMaxHeight = 48; |
447 | 2.38k | #ifdef LIBVNCSERVER_HAVE_LIBZ |
448 | 2.38k | cl->zrleData = NULL; |
449 | 2.38k | #endif |
450 | | |
451 | 2.38k | cl->copyRegion = sraRgnCreate(); |
452 | 2.38k | cl->copyDX = 0; |
453 | 2.38k | cl->copyDY = 0; |
454 | | |
455 | 2.38k | cl->modifiedRegion = |
456 | 2.38k | sraRgnCreateRect(0,0,rfbScreen->width,rfbScreen->height); |
457 | | |
458 | 2.38k | INIT_MUTEX(cl->updateMutex); |
459 | 2.38k | INIT_COND(cl->updateCond); |
460 | | |
461 | 2.38k | cl->requestedRegion = sraRgnCreate(); |
462 | | |
463 | 2.38k | cl->format = cl->screen->serverFormat; |
464 | 2.38k | cl->translateFn = rfbTranslateNone; |
465 | 2.38k | cl->translateLookupTable = NULL; |
466 | | |
467 | 2.38k | LOCK(rfbClientListMutex); |
468 | 2.38k | #if defined(LIBVNCSERVER_HAVE_LIBPTHREAD) || defined(LIBVNCSERVER_HAVE_WIN32THREADS) |
469 | 2.38k | cl->refCount = 0; |
470 | 2.38k | #endif |
471 | 2.38k | cl->next = rfbScreen->clientHead; |
472 | 2.38k | cl->prev = NULL; |
473 | 2.38k | if (rfbScreen->clientHead) |
474 | 0 | rfbScreen->clientHead->prev = cl; |
475 | | |
476 | 2.38k | rfbScreen->clientHead = cl; |
477 | 2.38k | UNLOCK(rfbClientListMutex); |
478 | | |
479 | 2.38k | #if defined(LIBVNCSERVER_HAVE_LIBZ) || defined(LIBVNCSERVER_HAVE_LIBPNG) |
480 | 2.38k | cl->tightQualityLevel = -1; |
481 | | #ifdef LIBVNCSERVER_HAVE_LIBJPEG |
482 | | cl->tightCompressLevel = TIGHT_DEFAULT_COMPRESSION; |
483 | | cl->turboSubsampLevel = TURBO_DEFAULT_SUBSAMP; |
484 | | { |
485 | | int i; |
486 | | for (i = 0; i < 4; i++) |
487 | | cl->zsActive[i] = FALSE; |
488 | | } |
489 | | #endif |
490 | 2.38k | #endif |
491 | | |
492 | 2.38k | cl->fileTransfer.fd = -1; |
493 | | |
494 | 2.38k | cl->enableCursorShapeUpdates = FALSE; |
495 | 2.38k | cl->enableCursorPosUpdates = FALSE; |
496 | 2.38k | cl->useRichCursorEncoding = FALSE; |
497 | 2.38k | cl->enableLastRectEncoding = FALSE; |
498 | 2.38k | cl->enableKeyboardLedState = FALSE; |
499 | 2.38k | cl->enableSupportedMessages = FALSE; |
500 | 2.38k | cl->enableSupportedEncodings = FALSE; |
501 | 2.38k | cl->enableServerIdentity = FALSE; |
502 | 2.38k | cl->lastKeyboardLedState = -1; |
503 | 2.38k | cl->cursorX = rfbScreen->cursorX; |
504 | 2.38k | cl->cursorY = rfbScreen->cursorY; |
505 | 2.38k | cl->useNewFBSize = FALSE; |
506 | 2.38k | cl->useExtDesktopSize = FALSE; |
507 | 2.38k | cl->requestedDesktopSizeChange = 0; |
508 | 2.38k | cl->lastDesktopSizeChangeError = 0; |
509 | | |
510 | 2.38k | #ifdef LIBVNCSERVER_HAVE_LIBZ |
511 | 2.38k | cl->compStreamInited = FALSE; |
512 | 2.38k | cl->compStream.total_in = 0; |
513 | 2.38k | cl->compStream.total_out = 0; |
514 | 2.38k | cl->compStream.zalloc = Z_NULL; |
515 | 2.38k | cl->compStream.zfree = Z_NULL; |
516 | 2.38k | cl->compStream.opaque = Z_NULL; |
517 | | |
518 | 2.38k | cl->zlibCompressLevel = 5; |
519 | 2.38k | #endif |
520 | | |
521 | 2.38k | cl->progressiveSliceY = 0; |
522 | | |
523 | 2.38k | cl->extensions = NULL; |
524 | | |
525 | 2.38k | cl->lastPtrX = -1; |
526 | | |
527 | 2.38k | #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD |
528 | 2.38k | cl->pipe_notify_client_thread[0] = -1; |
529 | 2.38k | cl->pipe_notify_client_thread[1] = -1; |
530 | 2.38k | #endif |
531 | | |
532 | | #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
533 | | #ifdef LIBVNCSERVER_WITH_WEBSOCKETS |
534 | | /* |
535 | | * Wait a few ms for the client to send WebSockets connection (TLS/SSL or plain) |
536 | | */ |
537 | | if (!webSocketsCheck(cl)) { |
538 | | /* Error reporting handled in webSocketsHandshake */ |
539 | | rfbCloseClient(cl); |
540 | | rfbClientConnectionGone(cl); |
541 | | return NULL; |
542 | | } |
543 | | #endif |
544 | | #endif |
545 | | |
546 | 2.38k | #ifdef LIBVNCSERVER_HAVE_LIBZ |
547 | 2.38k | cl->enableExtendedClipboard = FALSE; |
548 | 2.38k | cl->extClipboardUserCap = 0x1B000007; /* text, rtf, html, request, notify, provide */ |
549 | 2.38k | cl->extClipboardMaxUnsolicitedSize = 20 * (1 << 20); /* 20 MiB */ |
550 | 2.38k | cl->extClipboardData = NULL; |
551 | 2.38k | cl->extClipboardDataSize = 0; |
552 | 2.38k | #endif |
553 | | |
554 | 2.38k | sprintf(pv,rfbProtocolVersionFormat,rfbScreen->protocolMajorVersion, |
555 | 2.38k | rfbScreen->protocolMinorVersion); |
556 | | |
557 | 2.38k | if (rfbWriteExact(cl, pv, sz_rfbProtocolVersionMsg) < 0) { |
558 | 0 | rfbLogPerror("rfbNewClient: write"); |
559 | 0 | rfbCloseClient(cl); |
560 | 0 | rfbClientConnectionGone(cl); |
561 | 0 | return NULL; |
562 | 0 | } |
563 | 2.38k | } |
564 | | |
565 | 2.38k | for(extension = rfbGetExtensionIterator(); extension; |
566 | 2.38k | extension=extension->next) { |
567 | 0 | void* data = NULL; |
568 | | /* if the extension does not have a newClient method, it wants |
569 | | * to be initialized later. */ |
570 | 0 | if(extension->newClient && extension->newClient(cl, &data)) |
571 | 0 | rfbEnableExtension(cl, extension, data); |
572 | 0 | } |
573 | 2.38k | rfbReleaseExtensionIterator(); |
574 | | |
575 | 2.38k | switch (cl->screen->newClientHook(cl)) { |
576 | 0 | case RFB_CLIENT_ON_HOLD: |
577 | 0 | cl->onHold = TRUE; |
578 | 0 | break; |
579 | 2.38k | case RFB_CLIENT_ACCEPT: |
580 | 2.38k | cl->onHold = FALSE; |
581 | 2.38k | break; |
582 | 0 | case RFB_CLIENT_REFUSE: |
583 | 0 | rfbCloseClient(cl); |
584 | 0 | rfbClientConnectionGone(cl); |
585 | 0 | cl = NULL; |
586 | 0 | break; |
587 | 2.38k | } |
588 | 2.38k | return cl; |
589 | 2.38k | } |
590 | | |
591 | | rfbClientPtr |
592 | | rfbNewClient(rfbScreenInfoPtr rfbScreen, |
593 | | rfbSocket sock) |
594 | 2.38k | { |
595 | 2.38k | return(rfbNewTCPOrUDPClient(rfbScreen,sock,FALSE)); |
596 | 2.38k | } |
597 | | |
598 | | rfbClientPtr |
599 | | rfbNewUDPClient(rfbScreenInfoPtr rfbScreen) |
600 | 0 | { |
601 | 0 | return((rfbScreen->udpClient= |
602 | 0 | rfbNewTCPOrUDPClient(rfbScreen,rfbScreen->udpSock,TRUE))); |
603 | 0 | } |
604 | | |
605 | | /* |
606 | | * rfbClientConnectionGone is called from sockets.c just after a connection |
607 | | * has gone away. |
608 | | */ |
609 | | |
610 | | void |
611 | | rfbClientConnectionGone(rfbClientPtr cl) |
612 | 2.38k | { |
613 | | #if defined(LIBVNCSERVER_HAVE_LIBZ) && defined(LIBVNCSERVER_HAVE_LIBJPEG) |
614 | | int i; |
615 | | #endif |
616 | | |
617 | 2.38k | LOCK(rfbClientListMutex); |
618 | | |
619 | 2.38k | if (cl->prev) |
620 | 0 | cl->prev->next = cl->next; |
621 | 2.38k | else |
622 | 2.38k | cl->screen->clientHead = cl->next; |
623 | 2.38k | if (cl->next) |
624 | 0 | cl->next->prev = cl->prev; |
625 | | |
626 | 2.38k | UNLOCK(rfbClientListMutex); |
627 | | |
628 | 2.38k | #if defined(LIBVNCSERVER_HAVE_LIBPTHREAD) || defined(LIBVNCSERVER_HAVE_WIN32THREADS) |
629 | 2.38k | if (cl->screen->backgroundLoop) { |
630 | 0 | int i; |
631 | 0 | do { |
632 | 0 | LOCK(cl->refCountMutex); |
633 | 0 | i=cl->refCount; |
634 | 0 | if(i>0) |
635 | 0 | WAIT(cl->deleteCond,cl->refCountMutex); |
636 | 0 | UNLOCK(cl->refCountMutex); |
637 | 0 | } while(i>0); |
638 | 0 | } |
639 | 2.38k | #endif |
640 | | |
641 | 2.38k | if(cl->sock != RFB_INVALID_SOCKET) |
642 | 0 | rfbCloseSocket(cl->sock); |
643 | | |
644 | 2.38k | if (cl->scaledScreen!=NULL) |
645 | 2.38k | cl->scaledScreen->scaledScreenRefCount--; |
646 | | |
647 | 2.38k | #ifdef LIBVNCSERVER_HAVE_LIBZ |
648 | 2.38k | rfbFreeZrleData(cl); |
649 | | |
650 | | #ifdef LIBVNCSERVER_HAVE_LIBJPEG |
651 | | rfbFreeTightData(cl); |
652 | | #endif |
653 | 2.38k | #endif |
654 | | |
655 | 2.38k | rfbFreeUltraData(cl); |
656 | | |
657 | | /* free buffers holding pixel data before and after encoding */ |
658 | 2.38k | free(cl->beforeEncBuf); |
659 | 2.38k | free(cl->afterEncBuf); |
660 | | |
661 | 2.38k | if(cl->sock != RFB_INVALID_SOCKET) |
662 | 2.38k | FD_CLR(cl->sock,&(cl->screen->allFds)); |
663 | | |
664 | 2.38k | cl->clientGoneHook(cl); |
665 | | |
666 | 2.38k | rfbLog("Client %s gone\n",cl->host); |
667 | 2.38k | free(cl->host); |
668 | 2.38k | free(cl->repeaterId); |
669 | | |
670 | 2.38k | if (cl->wsctx != NULL){ |
671 | 0 | free(cl->wsctx); |
672 | 0 | cl->wsctx = NULL; |
673 | 0 | } |
674 | | |
675 | 2.38k | #ifdef LIBVNCSERVER_HAVE_LIBZ |
676 | | /* Release the compression state structures if any. */ |
677 | 2.38k | if ( cl->compStreamInited ) { |
678 | 0 | deflateEnd( &(cl->compStream) ); |
679 | 0 | } |
680 | | |
681 | 2.38k | free(cl->extClipboardData); |
682 | | |
683 | | #ifdef LIBVNCSERVER_HAVE_LIBJPEG |
684 | | for (i = 0; i < 4; i++) { |
685 | | if (cl->zsActive[i]) |
686 | | deflateEnd(&cl->zsStruct[i]); |
687 | | } |
688 | | #endif |
689 | 2.38k | #endif |
690 | | |
691 | 2.38k | if (cl->screen->pointerClient == cl) |
692 | 161 | cl->screen->pointerClient = NULL; |
693 | | |
694 | 2.38k | sraRgnDestroy(cl->modifiedRegion); |
695 | 2.38k | sraRgnDestroy(cl->requestedRegion); |
696 | 2.38k | sraRgnDestroy(cl->copyRegion); |
697 | | |
698 | 2.38k | free(cl->translateLookupTable); |
699 | | |
700 | 2.38k | TINI_COND(cl->updateCond); |
701 | 2.38k | TINI_MUTEX(cl->updateMutex); |
702 | | |
703 | | /* make sure outputMutex is unlocked before destroying */ |
704 | 2.38k | LOCK(cl->outputMutex); |
705 | 2.38k | UNLOCK(cl->outputMutex); |
706 | 2.38k | TINI_MUTEX(cl->outputMutex); |
707 | | |
708 | 2.38k | LOCK(cl->sendMutex); |
709 | 2.38k | UNLOCK(cl->sendMutex); |
710 | 2.38k | TINI_MUTEX(cl->sendMutex); |
711 | | |
712 | 2.38k | #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD |
713 | 2.38k | if (cl->screen->backgroundLoop) { |
714 | 0 | close(cl->pipe_notify_client_thread[0]); |
715 | 0 | close(cl->pipe_notify_client_thread[1]); |
716 | 0 | } |
717 | 2.38k | #endif |
718 | | |
719 | 2.38k | rfbPrintStats(cl); |
720 | 2.38k | rfbResetStats(cl); |
721 | | |
722 | 2.38k | free(cl); |
723 | 2.38k | } |
724 | | |
725 | | |
726 | | /* |
727 | | * rfbProcessClientMessage is called when there is data to read from a client. |
728 | | */ |
729 | | |
730 | | void |
731 | | rfbProcessClientMessage(rfbClientPtr cl) |
732 | 78.5k | { |
733 | 78.5k | switch (cl->state) { |
734 | 2.38k | case RFB_PROTOCOL_VERSION: |
735 | 2.38k | rfbProcessClientProtocolVersion(cl); |
736 | 2.38k | return; |
737 | 68 | case RFB_SECURITY_TYPE: |
738 | 68 | rfbProcessClientSecurityType(cl); |
739 | 68 | return; |
740 | 0 | case RFB_AUTHENTICATION: |
741 | 0 | rfbAuthProcessClientMessage(cl); |
742 | 0 | return; |
743 | 2.33k | case RFB_INITIALISATION: |
744 | 2.33k | case RFB_INITIALISATION_SHARED: |
745 | 2.33k | rfbProcessClientInitMessage(cl); |
746 | 2.33k | return; |
747 | 73.7k | default: |
748 | 73.7k | rfbProcessClientNormalMessage(cl); |
749 | 73.7k | return; |
750 | 78.5k | } |
751 | 78.5k | } |
752 | | |
753 | | |
754 | | /* |
755 | | * rfbProcessClientProtocolVersion is called when the client sends its |
756 | | * protocol version. |
757 | | */ |
758 | | |
759 | | static void |
760 | | rfbProcessClientProtocolVersion(rfbClientPtr cl) |
761 | 2.38k | { |
762 | 2.38k | rfbProtocolVersionMsg pv; |
763 | 2.38k | int n, major_, minor_; |
764 | | |
765 | 2.38k | if ((n = rfbReadExact(cl, pv, sz_rfbProtocolVersionMsg)) <= 0) { |
766 | 7 | if (n == 0) |
767 | 7 | rfbLog("rfbProcessClientProtocolVersion: client gone\n"); |
768 | 0 | else |
769 | 0 | rfbLogPerror("rfbProcessClientProtocolVersion: read"); |
770 | 7 | rfbCloseClient(cl); |
771 | 7 | return; |
772 | 7 | } |
773 | | |
774 | 2.38k | pv[sz_rfbProtocolVersionMsg] = 0; |
775 | 2.38k | if (sscanf(pv,rfbProtocolVersionFormat,&major_,&minor_) != 2) { |
776 | 5 | rfbErr("rfbProcessClientProtocolVersion: not a valid RFB client: %s\n", pv); |
777 | 5 | rfbCloseClient(cl); |
778 | 5 | return; |
779 | 5 | } |
780 | 2.37k | rfbLog("Client Protocol Version %d.%d\n", major_, minor_); |
781 | | |
782 | 2.37k | if (major_ != rfbProtocolMajorVersion) { |
783 | 17 | rfbErr("RFB protocol version mismatch - server %d.%d, client %d.%d", |
784 | 17 | cl->screen->protocolMajorVersion, cl->screen->protocolMinorVersion, |
785 | 17 | major_,minor_); |
786 | 17 | rfbCloseClient(cl); |
787 | 17 | return; |
788 | 17 | } |
789 | | |
790 | | /* Check for the minor version use either of the two standard version of RFB */ |
791 | | /* |
792 | | * UltraVNC Viewer detects FileTransfer compatible servers via rfb versions |
793 | | * 3.4, 3.6, 3.14, 3.16 |
794 | | * It's a bad method, but it is what they use to enable features... |
795 | | * maintaining RFB version compatibility across multiple servers is a pain |
796 | | * Should use something like ServerIdentity encoding |
797 | | */ |
798 | 2.35k | cl->protocolMajorVersion = major_; |
799 | 2.35k | cl->protocolMinorVersion = minor_; |
800 | | |
801 | 2.35k | rfbLog("Protocol version sent %d.%d, using %d.%d\n", |
802 | 2.35k | major_, minor_, rfbProtocolMajorVersion, cl->protocolMinorVersion); |
803 | | |
804 | 2.35k | rfbAuthNewClient(cl); |
805 | 2.35k | } |
806 | | |
807 | | |
808 | | void |
809 | | rfbClientSendString(rfbClientPtr cl, const char *reason) |
810 | 0 | { |
811 | 0 | char *buf; |
812 | 0 | int len = strlen(reason); |
813 | |
|
814 | 0 | rfbLog("rfbClientSendString(\"%s\")\n", reason); |
815 | |
|
816 | 0 | buf = (char *)malloc(4 + len); |
817 | 0 | if (buf) { |
818 | 0 | ((uint32_t *)buf)[0] = Swap32IfLE(len); |
819 | 0 | memcpy(buf + 4, reason, len); |
820 | |
|
821 | 0 | if (rfbWriteExact(cl, buf, 4 + len) < 0) |
822 | 0 | rfbLogPerror("rfbClientSendString: write"); |
823 | 0 | free(buf); |
824 | 0 | } |
825 | |
|
826 | 0 | rfbCloseClient(cl); |
827 | 0 | } |
828 | | |
829 | | /* |
830 | | * rfbClientConnFailed is called when a client connection has failed either |
831 | | * because it talks the wrong protocol or it has failed authentication. |
832 | | */ |
833 | | |
834 | | void |
835 | | rfbClientConnFailed(rfbClientPtr cl, |
836 | | const char *reason) |
837 | 0 | { |
838 | 0 | char *buf; |
839 | 0 | int len = strlen(reason); |
840 | |
|
841 | 0 | rfbLog("rfbClientConnFailed(\"%s\")\n", reason); |
842 | |
|
843 | 0 | buf = (char *)malloc(8 + len); |
844 | 0 | if (buf) { |
845 | 0 | ((uint32_t *)buf)[0] = Swap32IfLE(rfbConnFailed); |
846 | 0 | ((uint32_t *)buf)[1] = Swap32IfLE(len); |
847 | 0 | memcpy(buf + 8, reason, len); |
848 | |
|
849 | 0 | if (rfbWriteExact(cl, buf, 8 + len) < 0) |
850 | 0 | rfbLogPerror("rfbClientConnFailed: write"); |
851 | 0 | free(buf); |
852 | 0 | } |
853 | |
|
854 | 0 | rfbCloseClient(cl); |
855 | 0 | } |
856 | | |
857 | | |
858 | | /* |
859 | | * rfbProcessClientInitMessage is called when the client sends its |
860 | | * initialisation message. |
861 | | */ |
862 | | |
863 | | static void |
864 | | rfbProcessClientInitMessage(rfbClientPtr cl) |
865 | 2.33k | { |
866 | 2.33k | rfbClientInitMsg ci; |
867 | 2.33k | union { |
868 | 2.33k | char buf[256]; |
869 | 2.33k | rfbServerInitMsg si; |
870 | 2.33k | } u; |
871 | 2.33k | int len, n; |
872 | 2.33k | rfbClientIteratorPtr iterator; |
873 | 2.33k | rfbClientPtr otherCl; |
874 | 2.33k | rfbExtensionData* extension; |
875 | | |
876 | 2.33k | if (cl->state == RFB_INITIALISATION_SHARED) { |
877 | | /* In this case behave as though an implicit ClientInit message has |
878 | | * already been received with a shared-flag of true. */ |
879 | 1 | ci.shared = 1; |
880 | | /* Avoid the possibility of exposing the RFB_INITIALISATION_SHARED |
881 | | * state to calling software. */ |
882 | 1 | cl->state = RFB_INITIALISATION; |
883 | 2.33k | } else { |
884 | 2.33k | if ((n = rfbReadExact(cl, (char *)&ci,sz_rfbClientInitMsg)) <= 0) { |
885 | 31 | if (n == 0) |
886 | 31 | rfbLog("rfbProcessClientInitMessage: client gone\n"); |
887 | 0 | else |
888 | 0 | rfbLogPerror("rfbProcessClientInitMessage: read"); |
889 | 31 | rfbCloseClient(cl); |
890 | 31 | return; |
891 | 31 | } |
892 | 2.33k | } |
893 | | |
894 | 2.30k | memset(u.buf,0,sizeof(u.buf)); |
895 | | |
896 | 2.30k | u.si.framebufferWidth = Swap16IfLE(cl->screen->width); |
897 | 2.30k | u.si.framebufferHeight = Swap16IfLE(cl->screen->height); |
898 | 2.30k | u.si.format = cl->screen->serverFormat; |
899 | 2.30k | u.si.format.redMax = Swap16IfLE(u.si.format.redMax); |
900 | 2.30k | u.si.format.greenMax = Swap16IfLE(u.si.format.greenMax); |
901 | 2.30k | u.si.format.blueMax = Swap16IfLE(u.si.format.blueMax); |
902 | | |
903 | 2.30k | strncpy(u.buf + sz_rfbServerInitMsg, cl->screen->desktopName, 127); |
904 | 2.30k | len = strlen(u.buf + sz_rfbServerInitMsg); |
905 | 2.30k | u.si.nameLength = Swap32IfLE(len); |
906 | | |
907 | 2.30k | if (rfbWriteExact(cl, u.buf, sz_rfbServerInitMsg + len) < 0) { |
908 | 0 | rfbLogPerror("rfbProcessClientInitMessage: write"); |
909 | 0 | rfbCloseClient(cl); |
910 | 0 | return; |
911 | 0 | } |
912 | | |
913 | 2.30k | for(extension = cl->extensions; extension;) { |
914 | 0 | rfbExtensionData* next = extension->next; |
915 | 0 | if(extension->extension->init && |
916 | 0 | !extension->extension->init(cl, extension->data)) |
917 | | /* extension requested that it be removed */ |
918 | 0 | rfbDisableExtension(cl, extension->extension); |
919 | 0 | extension = next; |
920 | 0 | } |
921 | | |
922 | 2.30k | cl->state = RFB_NORMAL; |
923 | | |
924 | 2.30k | if (!cl->reverseConnection && |
925 | 2.30k | (cl->screen->neverShared || (!cl->screen->alwaysShared && !ci.shared))) { |
926 | | |
927 | 419 | if (cl->screen->dontDisconnect) { |
928 | 0 | iterator = rfbGetClientIterator(cl->screen); |
929 | 0 | while ((otherCl = rfbClientIteratorNext(iterator)) != NULL) { |
930 | 0 | if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) { |
931 | 0 | rfbLog("-dontdisconnect: Not shared & existing client\n"); |
932 | 0 | rfbLog(" refusing new client %s\n", cl->host); |
933 | 0 | rfbCloseClient(cl); |
934 | 0 | rfbReleaseClientIterator(iterator); |
935 | 0 | return; |
936 | 0 | } |
937 | 0 | } |
938 | 0 | rfbReleaseClientIterator(iterator); |
939 | 419 | } else { |
940 | 419 | iterator = rfbGetClientIterator(cl->screen); |
941 | 419 | rfbClientPtr nextCl, otherCl = rfbClientIteratorNext(iterator); |
942 | 419 | while (otherCl) { |
943 | 0 | nextCl = rfbClientIteratorNext(iterator); |
944 | 0 | if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) { |
945 | 0 | rfbLog("Not shared - closing connection to client %s\n", |
946 | 0 | otherCl->host); |
947 | 0 | rfbCloseClient(otherCl); |
948 | 0 | } |
949 | 0 | otherCl = nextCl; |
950 | 0 | } |
951 | 419 | rfbReleaseClientIterator(iterator); |
952 | 419 | } |
953 | 419 | } |
954 | 2.30k | } |
955 | | |
956 | | /* The values come in based on the scaled screen, we need to convert them to |
957 | | * values based on the man screen's coordinate system |
958 | | */ |
959 | | static rfbBool rectSwapIfLEAndClip(uint16_t* x,uint16_t* y,uint16_t* w,uint16_t* h, |
960 | | rfbClientPtr cl) |
961 | 4.50k | { |
962 | 4.50k | int x1=Swap16IfLE(*x); |
963 | 4.50k | int y1=Swap16IfLE(*y); |
964 | 4.50k | int w1=Swap16IfLE(*w); |
965 | 4.50k | int h1=Swap16IfLE(*h); |
966 | | |
967 | 4.50k | rfbScaledCorrection(cl->scaledScreen, cl->screen, &x1, &y1, &w1, &h1, "rectSwapIfLEAndClip"); |
968 | 4.50k | *x = x1; |
969 | 4.50k | *y = y1; |
970 | 4.50k | *w = w1; |
971 | 4.50k | *h = h1; |
972 | | |
973 | 4.50k | if(*w>cl->screen->width-*x) |
974 | 2.29k | *w=cl->screen->width-*x; |
975 | | /* possible underflow */ |
976 | 4.50k | if(*w>cl->screen->width-*x) |
977 | 650 | return FALSE; |
978 | 3.85k | if(*h>cl->screen->height-*y) |
979 | 1.87k | *h=cl->screen->height-*y; |
980 | 3.85k | if(*h>cl->screen->height-*y) |
981 | 942 | return FALSE; |
982 | | |
983 | 2.91k | return TRUE; |
984 | 3.85k | } |
985 | | |
986 | | /* |
987 | | * Send keyboard state (PointerPos pseudo-encoding). |
988 | | */ |
989 | | |
990 | | rfbBool |
991 | | rfbSendKeyboardLedState(rfbClientPtr cl) |
992 | 0 | { |
993 | 0 | rfbFramebufferUpdateRectHeader rect; |
994 | |
|
995 | 0 | if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) { |
996 | 0 | if (!rfbSendUpdateBuf(cl)) |
997 | 0 | return FALSE; |
998 | 0 | } |
999 | | |
1000 | 0 | rect.encoding = Swap32IfLE(rfbEncodingKeyboardLedState); |
1001 | 0 | rect.r.x = Swap16IfLE(cl->lastKeyboardLedState); |
1002 | 0 | rect.r.y = 0; |
1003 | 0 | rect.r.w = 0; |
1004 | 0 | rect.r.h = 0; |
1005 | |
|
1006 | 0 | memcpy(&cl->updateBuf[cl->ublen], (char *)&rect, |
1007 | 0 | sz_rfbFramebufferUpdateRectHeader); |
1008 | 0 | cl->ublen += sz_rfbFramebufferUpdateRectHeader; |
1009 | |
|
1010 | 0 | rfbStatRecordEncodingSent(cl, rfbEncodingKeyboardLedState, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader); |
1011 | |
|
1012 | 0 | if (!rfbSendUpdateBuf(cl)) |
1013 | 0 | return FALSE; |
1014 | | |
1015 | 0 | return TRUE; |
1016 | 0 | } |
1017 | | |
1018 | | |
1019 | 0 | #define rfbSetBit(buffer, position) (buffer[(position & 255) / 8] |= (1 << (position % 8))) |
1020 | | |
1021 | | /* |
1022 | | * Send rfbEncodingSupportedMessages. |
1023 | | */ |
1024 | | |
1025 | | rfbBool |
1026 | | rfbSendSupportedMessages(rfbClientPtr cl) |
1027 | 0 | { |
1028 | 0 | rfbFramebufferUpdateRectHeader rect; |
1029 | 0 | rfbSupportedMessages msgs; |
1030 | |
|
1031 | 0 | if (cl->ublen + sz_rfbFramebufferUpdateRectHeader |
1032 | 0 | + sz_rfbSupportedMessages > UPDATE_BUF_SIZE) { |
1033 | 0 | if (!rfbSendUpdateBuf(cl)) |
1034 | 0 | return FALSE; |
1035 | 0 | } |
1036 | | |
1037 | 0 | rect.encoding = Swap32IfLE(rfbEncodingSupportedMessages); |
1038 | 0 | rect.r.x = 0; |
1039 | 0 | rect.r.y = 0; |
1040 | 0 | rect.r.w = Swap16IfLE(sz_rfbSupportedMessages); |
1041 | 0 | rect.r.h = 0; |
1042 | |
|
1043 | 0 | memcpy(&cl->updateBuf[cl->ublen], (char *)&rect, |
1044 | 0 | sz_rfbFramebufferUpdateRectHeader); |
1045 | 0 | cl->ublen += sz_rfbFramebufferUpdateRectHeader; |
1046 | |
|
1047 | 0 | memset((char *)&msgs, 0, sz_rfbSupportedMessages); |
1048 | 0 | rfbSetBit(msgs.client2server, rfbSetPixelFormat); |
1049 | 0 | rfbSetBit(msgs.client2server, rfbFixColourMapEntries); |
1050 | 0 | rfbSetBit(msgs.client2server, rfbSetEncodings); |
1051 | 0 | rfbSetBit(msgs.client2server, rfbFramebufferUpdateRequest); |
1052 | 0 | rfbSetBit(msgs.client2server, rfbKeyEvent); |
1053 | 0 | rfbSetBit(msgs.client2server, rfbPointerEvent); |
1054 | 0 | rfbSetBit(msgs.client2server, rfbClientCutText); |
1055 | 0 | rfbSetBit(msgs.client2server, rfbFileTransfer); |
1056 | 0 | rfbSetBit(msgs.client2server, rfbSetScale); |
1057 | | /*rfbSetBit(msgs.client2server, rfbSetServerInput); */ |
1058 | | /*rfbSetBit(msgs.client2server, rfbSetSW); */ |
1059 | | /*rfbSetBit(msgs.client2server, rfbTextChat); */ |
1060 | 0 | rfbSetBit(msgs.client2server, rfbPalmVNCSetScaleFactor); |
1061 | |
|
1062 | 0 | rfbSetBit(msgs.server2client, rfbFramebufferUpdate); |
1063 | 0 | rfbSetBit(msgs.server2client, rfbSetColourMapEntries); |
1064 | 0 | rfbSetBit(msgs.server2client, rfbBell); |
1065 | 0 | rfbSetBit(msgs.server2client, rfbServerCutText); |
1066 | 0 | rfbSetBit(msgs.server2client, rfbResizeFrameBuffer); |
1067 | 0 | rfbSetBit(msgs.server2client, rfbPalmVNCReSizeFrameBuffer); |
1068 | 0 | rfbSetBit(msgs.client2server, rfbSetDesktopSize); |
1069 | |
|
1070 | 0 | if (cl->screen->xvpHook) { |
1071 | 0 | rfbSetBit(msgs.client2server, rfbXvp); |
1072 | 0 | rfbSetBit(msgs.server2client, rfbXvp); |
1073 | 0 | } |
1074 | |
|
1075 | 0 | memcpy(&cl->updateBuf[cl->ublen], (char *)&msgs, sz_rfbSupportedMessages); |
1076 | 0 | cl->ublen += sz_rfbSupportedMessages; |
1077 | |
|
1078 | 0 | rfbStatRecordEncodingSent(cl, rfbEncodingSupportedMessages, |
1079 | 0 | sz_rfbFramebufferUpdateRectHeader+sz_rfbSupportedMessages, |
1080 | 0 | sz_rfbFramebufferUpdateRectHeader+sz_rfbSupportedMessages); |
1081 | 0 | if (!rfbSendUpdateBuf(cl)) |
1082 | 0 | return FALSE; |
1083 | | |
1084 | 0 | return TRUE; |
1085 | 0 | } |
1086 | | |
1087 | | |
1088 | | |
1089 | | /* |
1090 | | * Send rfbEncodingSupportedEncodings. |
1091 | | */ |
1092 | | |
1093 | | rfbBool |
1094 | | rfbSendSupportedEncodings(rfbClientPtr cl) |
1095 | 0 | { |
1096 | 0 | rfbFramebufferUpdateRectHeader rect; |
1097 | 0 | static uint32_t supported[] = { |
1098 | 0 | rfbEncodingRaw, |
1099 | 0 | rfbEncodingCopyRect, |
1100 | 0 | rfbEncodingRRE, |
1101 | 0 | rfbEncodingCoRRE, |
1102 | 0 | rfbEncodingHextile, |
1103 | 0 | #ifdef LIBVNCSERVER_HAVE_LIBZ |
1104 | 0 | rfbEncodingZlib, |
1105 | 0 | rfbEncodingZRLE, |
1106 | 0 | rfbEncodingZYWRLE, |
1107 | 0 | #endif |
1108 | | #ifdef LIBVNCSERVER_HAVE_LIBJPEG |
1109 | | rfbEncodingTight, |
1110 | | #endif |
1111 | | #ifdef LIBVNCSERVER_HAVE_LIBPNG |
1112 | | rfbEncodingTightPng, |
1113 | | #endif |
1114 | 0 | rfbEncodingUltra, |
1115 | 0 | rfbEncodingUltraZip, |
1116 | 0 | rfbEncodingXCursor, |
1117 | 0 | rfbEncodingRichCursor, |
1118 | 0 | rfbEncodingPointerPos, |
1119 | 0 | rfbEncodingLastRect, |
1120 | 0 | rfbEncodingNewFBSize, |
1121 | 0 | rfbEncodingExtDesktopSize, |
1122 | 0 | rfbEncodingKeyboardLedState, |
1123 | 0 | rfbEncodingSupportedMessages, |
1124 | 0 | rfbEncodingSupportedEncodings, |
1125 | 0 | rfbEncodingServerIdentity, |
1126 | 0 | #ifdef LIBVNCSERVER_HAVE_LIBZ |
1127 | 0 | rfbEncodingExtendedClipboard, |
1128 | 0 | #endif |
1129 | 0 | }; |
1130 | 0 | uint32_t nEncodings = sizeof(supported) / sizeof(supported[0]), i; |
1131 | | |
1132 | | /* think rfbSetEncodingsMsg */ |
1133 | |
|
1134 | 0 | if (cl->ublen + sz_rfbFramebufferUpdateRectHeader |
1135 | 0 | + (nEncodings * sizeof(uint32_t)) > UPDATE_BUF_SIZE) { |
1136 | 0 | if (!rfbSendUpdateBuf(cl)) |
1137 | 0 | return FALSE; |
1138 | 0 | } |
1139 | | |
1140 | 0 | rect.encoding = Swap32IfLE(rfbEncodingSupportedEncodings); |
1141 | 0 | rect.r.x = 0; |
1142 | 0 | rect.r.y = 0; |
1143 | 0 | rect.r.w = Swap16IfLE(nEncodings * sizeof(uint32_t)); |
1144 | 0 | rect.r.h = Swap16IfLE(nEncodings); |
1145 | |
|
1146 | 0 | memcpy(&cl->updateBuf[cl->ublen], (char *)&rect, |
1147 | 0 | sz_rfbFramebufferUpdateRectHeader); |
1148 | 0 | cl->ublen += sz_rfbFramebufferUpdateRectHeader; |
1149 | |
|
1150 | 0 | for (i = 0; i < nEncodings; i++) { |
1151 | 0 | uint32_t encoding = Swap32IfLE(supported[i]); |
1152 | 0 | memcpy(&cl->updateBuf[cl->ublen], (char *)&encoding, sizeof(encoding)); |
1153 | 0 | cl->ublen += sizeof(encoding); |
1154 | 0 | } |
1155 | |
|
1156 | 0 | rfbStatRecordEncodingSent(cl, rfbEncodingSupportedEncodings, |
1157 | 0 | sz_rfbFramebufferUpdateRectHeader+(nEncodings * sizeof(uint32_t)), |
1158 | 0 | sz_rfbFramebufferUpdateRectHeader+(nEncodings * sizeof(uint32_t))); |
1159 | |
|
1160 | 0 | if (!rfbSendUpdateBuf(cl)) |
1161 | 0 | return FALSE; |
1162 | | |
1163 | 0 | return TRUE; |
1164 | 0 | } |
1165 | | |
1166 | | |
1167 | | void |
1168 | | rfbSetServerVersionIdentity(rfbScreenInfoPtr screen, char *fmt, ...) |
1169 | 0 | { |
1170 | 0 | char buffer[256]; |
1171 | 0 | va_list ap; |
1172 | | |
1173 | 0 | va_start(ap, fmt); |
1174 | 0 | vsnprintf(buffer, sizeof(buffer)-1, fmt, ap); |
1175 | 0 | va_end(ap); |
1176 | | |
1177 | 0 | free(screen->versionString); |
1178 | 0 | screen->versionString = strdup(buffer); |
1179 | 0 | } |
1180 | | |
1181 | | /* |
1182 | | * Send rfbEncodingServerIdentity. |
1183 | | */ |
1184 | | |
1185 | | rfbBool |
1186 | | rfbSendServerIdentity(rfbClientPtr cl) |
1187 | 0 | { |
1188 | 0 | rfbFramebufferUpdateRectHeader rect; |
1189 | 0 | char buffer[512]; |
1190 | | |
1191 | | /* tack on our library version */ |
1192 | 0 | snprintf(buffer,sizeof(buffer)-1, "%s (%s)", |
1193 | 0 | (cl->screen->versionString==NULL ? "unknown" : cl->screen->versionString), |
1194 | 0 | LIBVNCSERVER_PACKAGE_STRING); |
1195 | |
|
1196 | 0 | if (cl->ublen + sz_rfbFramebufferUpdateRectHeader |
1197 | 0 | + (strlen(buffer)+1) > UPDATE_BUF_SIZE) { |
1198 | 0 | if (!rfbSendUpdateBuf(cl)) |
1199 | 0 | return FALSE; |
1200 | 0 | } |
1201 | | |
1202 | 0 | rect.encoding = Swap32IfLE(rfbEncodingServerIdentity); |
1203 | 0 | rect.r.x = 0; |
1204 | 0 | rect.r.y = 0; |
1205 | 0 | rect.r.w = Swap16IfLE(strlen(buffer)+1); |
1206 | 0 | rect.r.h = 0; |
1207 | |
|
1208 | 0 | memcpy(&cl->updateBuf[cl->ublen], (char *)&rect, |
1209 | 0 | sz_rfbFramebufferUpdateRectHeader); |
1210 | 0 | cl->ublen += sz_rfbFramebufferUpdateRectHeader; |
1211 | |
|
1212 | 0 | memcpy(&cl->updateBuf[cl->ublen], buffer, strlen(buffer)+1); |
1213 | 0 | cl->ublen += strlen(buffer)+1; |
1214 | |
|
1215 | 0 | rfbStatRecordEncodingSent(cl, rfbEncodingServerIdentity, |
1216 | 0 | sz_rfbFramebufferUpdateRectHeader+strlen(buffer)+1, |
1217 | 0 | sz_rfbFramebufferUpdateRectHeader+strlen(buffer)+1); |
1218 | | |
1219 | |
|
1220 | 0 | if (!rfbSendUpdateBuf(cl)) |
1221 | 0 | return FALSE; |
1222 | | |
1223 | 0 | return TRUE; |
1224 | 0 | } |
1225 | | |
1226 | | /* |
1227 | | * Send an xvp server message |
1228 | | */ |
1229 | | |
1230 | | rfbBool |
1231 | | rfbSendXvp(rfbClientPtr cl, uint8_t version, uint8_t code) |
1232 | 33.6k | { |
1233 | 33.6k | rfbXvpMsg xvp; |
1234 | | |
1235 | 33.6k | xvp.type = rfbXvp; |
1236 | 33.6k | xvp.pad = 0; |
1237 | 33.6k | xvp.version = version; |
1238 | 33.6k | xvp.code = code; |
1239 | | |
1240 | 33.6k | LOCK(cl->sendMutex); |
1241 | 33.6k | if (rfbWriteExact(cl, (char *)&xvp, sz_rfbXvpMsg) < 0) { |
1242 | 0 | rfbLogPerror("rfbSendXvp: write"); |
1243 | 0 | rfbCloseClient(cl); |
1244 | 0 | } |
1245 | 33.6k | UNLOCK(cl->sendMutex); |
1246 | | |
1247 | 33.6k | rfbStatRecordMessageSent(cl, rfbXvp, sz_rfbXvpMsg, sz_rfbXvpMsg); |
1248 | | |
1249 | 33.6k | return TRUE; |
1250 | 33.6k | } |
1251 | | |
1252 | | |
1253 | | rfbBool rfbSendTextChatMessage(rfbClientPtr cl, uint32_t length, char *buffer) |
1254 | 0 | { |
1255 | 0 | rfbTextChatMsg tc; |
1256 | 0 | int bytesToSend=0; |
1257 | |
|
1258 | 0 | memset((char *)&tc, 0, sizeof(tc)); |
1259 | 0 | tc.type = rfbTextChat; |
1260 | 0 | tc.length = Swap32IfLE(length); |
1261 | | |
1262 | 0 | switch(length) { |
1263 | 0 | case rfbTextChatOpen: |
1264 | 0 | case rfbTextChatClose: |
1265 | 0 | case rfbTextChatFinished: |
1266 | 0 | bytesToSend=0; |
1267 | 0 | break; |
1268 | 0 | default: |
1269 | 0 | bytesToSend=length; |
1270 | 0 | if (bytesToSend>rfbTextMaxSize) |
1271 | 0 | bytesToSend=rfbTextMaxSize; |
1272 | 0 | } |
1273 | | |
1274 | 0 | if (cl->ublen + sz_rfbTextChatMsg + bytesToSend > UPDATE_BUF_SIZE) { |
1275 | 0 | if (!rfbSendUpdateBuf(cl)) |
1276 | 0 | return FALSE; |
1277 | 0 | } |
1278 | | |
1279 | 0 | memcpy(&cl->updateBuf[cl->ublen], (char *)&tc, sz_rfbTextChatMsg); |
1280 | 0 | cl->ublen += sz_rfbTextChatMsg; |
1281 | 0 | if (bytesToSend>0) { |
1282 | 0 | memcpy(&cl->updateBuf[cl->ublen], buffer, bytesToSend); |
1283 | 0 | cl->ublen += bytesToSend; |
1284 | 0 | } |
1285 | 0 | rfbStatRecordMessageSent(cl, rfbTextChat, sz_rfbTextChatMsg+bytesToSend, sz_rfbTextChatMsg+bytesToSend); |
1286 | |
|
1287 | 0 | if (!rfbSendUpdateBuf(cl)) |
1288 | 0 | return FALSE; |
1289 | | |
1290 | 0 | return TRUE; |
1291 | 0 | } |
1292 | | |
1293 | | #define FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN(msg, cl, ret) \ |
1294 | 2 | if ((cl->screen->getFileTransferPermission != NULL \ |
1295 | 2 | && cl->screen->getFileTransferPermission(cl) != TRUE) \ |
1296 | 2 | || cl->screen->permitFileTransfer != TRUE) { \ |
1297 | 2 | rfbLog("%sUltra File Transfer is disabled, dropping client: %s\n", msg, cl->host); \ |
1298 | 2 | rfbCloseClient(cl); \ |
1299 | 2 | return ret; \ |
1300 | 2 | } |
1301 | | |
1302 | | int DB = 1; |
1303 | | |
1304 | | rfbBool rfbSendFileTransferMessage(rfbClientPtr cl, uint8_t contentType, uint8_t contentParam, uint32_t size, uint32_t length, const char *buffer) |
1305 | 0 | { |
1306 | 0 | rfbFileTransferMsg ft; |
1307 | 0 | ft.type = rfbFileTransfer; |
1308 | 0 | ft.contentType = contentType; |
1309 | 0 | ft.contentParam = contentParam; |
1310 | 0 | ft.pad = 0; /* UltraVNC did not Swap16LE(ft.contentParam) (Looks like it might be BigEndian) */ |
1311 | 0 | ft.size = Swap32IfLE(size); |
1312 | 0 | ft.length = Swap32IfLE(length); |
1313 | | |
1314 | 0 | FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE); |
1315 | | /* |
1316 | | rfbLog("rfbSendFileTransferMessage( %dtype, %dparam, %dsize, %dlen, %p)\n", contentType, contentParam, size, length, buffer); |
1317 | | */ |
1318 | 0 | LOCK(cl->sendMutex); |
1319 | 0 | if (rfbWriteExact(cl, (char *)&ft, sz_rfbFileTransferMsg) < 0) { |
1320 | 0 | rfbLogPerror("rfbSendFileTransferMessage: write"); |
1321 | 0 | rfbCloseClient(cl); |
1322 | 0 | UNLOCK(cl->sendMutex); |
1323 | 0 | return FALSE; |
1324 | 0 | } |
1325 | | |
1326 | 0 | if (length>0) |
1327 | 0 | { |
1328 | 0 | if (rfbWriteExact(cl, buffer, length) < 0) { |
1329 | 0 | rfbLogPerror("rfbSendFileTransferMessage: write"); |
1330 | 0 | rfbCloseClient(cl); |
1331 | 0 | UNLOCK(cl->sendMutex); |
1332 | 0 | return FALSE; |
1333 | 0 | } |
1334 | 0 | } |
1335 | 0 | UNLOCK(cl->sendMutex); |
1336 | |
|
1337 | 0 | rfbStatRecordMessageSent(cl, rfbFileTransfer, sz_rfbFileTransferMsg+length, sz_rfbFileTransferMsg+length); |
1338 | |
|
1339 | 0 | return TRUE; |
1340 | 0 | } |
1341 | | |
1342 | | |
1343 | | /* |
1344 | | * UltraVNC uses Windows Structures |
1345 | | */ |
1346 | 0 | #define MAX_PATH 260 |
1347 | | |
1348 | | typedef struct { |
1349 | | uint32_t dwLowDateTime; |
1350 | | uint32_t dwHighDateTime; |
1351 | | } RFB_FILETIME; |
1352 | | |
1353 | | typedef struct { |
1354 | | uint32_t dwFileAttributes; |
1355 | | RFB_FILETIME ftCreationTime; |
1356 | | RFB_FILETIME ftLastAccessTime; |
1357 | | RFB_FILETIME ftLastWriteTime; |
1358 | | uint32_t nFileSizeHigh; |
1359 | | uint32_t nFileSizeLow; |
1360 | | uint32_t dwReserved0; |
1361 | | uint32_t dwReserved1; |
1362 | | uint8_t cFileName[ MAX_PATH ]; |
1363 | | uint8_t cAlternateFileName[ 14 ]; |
1364 | | } RFB_FIND_DATA; |
1365 | | |
1366 | | #define RFB_FILE_ATTRIBUTE_READONLY 0x1 |
1367 | | #define RFB_FILE_ATTRIBUTE_HIDDEN 0x2 |
1368 | | #define RFB_FILE_ATTRIBUTE_SYSTEM 0x4 |
1369 | | #define RFB_FILE_ATTRIBUTE_DIRECTORY 0x10 |
1370 | | #define RFB_FILE_ATTRIBUTE_ARCHIVE 0x20 |
1371 | | #define RFB_FILE_ATTRIBUTE_NORMAL 0x80 |
1372 | | #define RFB_FILE_ATTRIBUTE_TEMPORARY 0x100 |
1373 | | #define RFB_FILE_ATTRIBUTE_COMPRESSED 0x800 |
1374 | | |
1375 | | rfbBool rfbFilenameTranslate2UNIX(rfbClientPtr cl, /* in */ char *path, /* out */ char *unixPath, size_t unixPathMaxLen) |
1376 | 0 | { |
1377 | 0 | int x; |
1378 | 0 | char *home=NULL; |
1379 | |
|
1380 | 0 | FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE); |
1381 | | |
1382 | | /* |
1383 | | * Do not use strncpy() - truncating the file name would probably have undesirable side effects |
1384 | | * Instead check if destination buffer is big enough |
1385 | | */ |
1386 | 0 | if (strlen(path) >= unixPathMaxLen) |
1387 | 0 | return FALSE; |
1388 | | |
1389 | | /* C: */ |
1390 | 0 | if (path[0]=='C' && path[1]==':') |
1391 | 0 | strcpy(unixPath, &path[2]); |
1392 | 0 | else |
1393 | 0 | { |
1394 | 0 | home = getenv("HOME"); |
1395 | 0 | if (home!=NULL) |
1396 | 0 | { |
1397 | | /* Re-check buffer size */ |
1398 | 0 | if ((strlen(path) + strlen(home) + 1) >= unixPathMaxLen) |
1399 | 0 | return FALSE; |
1400 | | |
1401 | 0 | strcpy(unixPath, home); |
1402 | 0 | strcat(unixPath,"/"); |
1403 | 0 | strcat(unixPath, path); |
1404 | 0 | } |
1405 | 0 | else |
1406 | 0 | strcpy(unixPath, path); |
1407 | 0 | } |
1408 | 0 | for (x=0;x<strlen(unixPath);x++) |
1409 | 0 | if (unixPath[x]=='\\') unixPath[x]='/'; |
1410 | 0 | return TRUE; |
1411 | 0 | } |
1412 | | |
1413 | | rfbBool rfbFilenameTranslate2DOS(rfbClientPtr cl, char *unixPath, char *path) |
1414 | 0 | { |
1415 | 0 | int x; |
1416 | |
|
1417 | 0 | FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE); |
1418 | |
|
1419 | 0 | sprintf(path,"C:%s", unixPath); |
1420 | 0 | for (x=2;x<strlen(path);x++) |
1421 | 0 | if (path[x]=='/') path[x]='\\'; |
1422 | 0 | return TRUE; |
1423 | 0 | } |
1424 | | |
1425 | | rfbBool rfbSendDirContent(rfbClientPtr cl, int length, char *buffer) |
1426 | 0 | { |
1427 | 0 | char retfilename[MAX_PATH*2]; |
1428 | 0 | char path[MAX_PATH]; |
1429 | 0 | struct stat statbuf; |
1430 | 0 | RFB_FIND_DATA win32filename; |
1431 | 0 | int nOptLen = 0, retval=0; |
1432 | | #ifdef WIN32 |
1433 | | WIN32_FIND_DATAA winFindData; |
1434 | | HANDLE findHandle; |
1435 | | int pathLen, basePathLength; |
1436 | | char *basePath; |
1437 | | #else |
1438 | 0 | DIR *dirp=NULL; |
1439 | 0 | struct dirent *direntp=NULL; |
1440 | 0 | #endif |
1441 | |
|
1442 | 0 | FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE); |
1443 | | |
1444 | | /* Client thinks we are Winblows */ |
1445 | 0 | if (!rfbFilenameTranslate2UNIX(cl, buffer, path, sizeof(path))) |
1446 | 0 | return FALSE; |
1447 | | |
1448 | 0 | if (DB) rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDirContent: \"%s\"->\"%s\"\n",buffer, path); |
1449 | |
|
1450 | | #ifdef WIN32 |
1451 | | // Create a search string, like C:\folder\* |
1452 | | |
1453 | | pathLen = strlen(path); |
1454 | | basePath = malloc(pathLen + 3); |
1455 | | memcpy(basePath, path, pathLen); |
1456 | | basePathLength = pathLen; |
1457 | | basePath[basePathLength] = '\\'; |
1458 | | basePath[basePathLength + 1] = '*'; |
1459 | | basePath[basePathLength + 2] = '\0'; |
1460 | | |
1461 | | // Start a search |
1462 | | memset(&winFindData, 0, sizeof(winFindData)); |
1463 | | findHandle = FindFirstFileA(path, &winFindData); |
1464 | | free(basePath); |
1465 | | |
1466 | | if (findHandle == INVALID_HANDLE_VALUE) |
1467 | | #else |
1468 | 0 | dirp=opendir(path); |
1469 | 0 | if (dirp==NULL) |
1470 | 0 | #endif |
1471 | 0 | return rfbSendFileTransferMessage(cl, rfbDirPacket, rfbADirectory, 0, 0, NULL); |
1472 | | |
1473 | | /* send back the path name (necessary for links) */ |
1474 | 0 | if (rfbSendFileTransferMessage(cl, rfbDirPacket, rfbADirectory, 0, length, buffer)==FALSE) return FALSE; |
1475 | | |
1476 | | #ifdef WIN32 |
1477 | | while (findHandle != INVALID_HANDLE_VALUE) |
1478 | | #else |
1479 | 0 | for (direntp=readdir(dirp); direntp!=NULL; direntp=readdir(dirp)) |
1480 | 0 | #endif |
1481 | 0 | { |
1482 | | /* get stats */ |
1483 | | #ifdef WIN32 |
1484 | | snprintf(retfilename,sizeof(retfilename),"%s/%s", path, winFindData.cFileName); |
1485 | | #else |
1486 | 0 | snprintf(retfilename,sizeof(retfilename),"%s/%s", path, direntp->d_name); |
1487 | 0 | #endif |
1488 | 0 | retval = stat(retfilename, &statbuf); |
1489 | |
|
1490 | 0 | if (retval==0) |
1491 | 0 | { |
1492 | 0 | memset((char *)&win32filename, 0, sizeof(win32filename)); |
1493 | | #ifdef WIN32 |
1494 | | win32filename.dwFileAttributes = winFindData.dwFileAttributes; |
1495 | | win32filename.ftCreationTime.dwLowDateTime = winFindData.ftCreationTime.dwLowDateTime; |
1496 | | win32filename.ftCreationTime.dwHighDateTime = winFindData.ftCreationTime.dwHighDateTime; |
1497 | | win32filename.ftLastAccessTime.dwLowDateTime = winFindData.ftLastAccessTime.dwLowDateTime; |
1498 | | win32filename.ftLastAccessTime.dwHighDateTime = winFindData.ftLastAccessTime.dwHighDateTime; |
1499 | | win32filename.ftLastWriteTime.dwLowDateTime = winFindData.ftLastWriteTime.dwLowDateTime; |
1500 | | win32filename.ftLastWriteTime.dwHighDateTime = winFindData.ftLastWriteTime.dwHighDateTime; |
1501 | | win32filename.nFileSizeLow = winFindData.nFileSizeLow; |
1502 | | win32filename.nFileSizeHigh = winFindData.nFileSizeHigh; |
1503 | | win32filename.dwReserved0 = winFindData.dwReserved0; |
1504 | | win32filename.dwReserved1 = winFindData.dwReserved1; |
1505 | | strcpy((char *)win32filename.cFileName, winFindData.cFileName); |
1506 | | strcpy((char *)win32filename.cAlternateFileName, winFindData.cAlternateFileName); |
1507 | | #else |
1508 | 0 | win32filename.dwFileAttributes = Swap32IfBE(RFB_FILE_ATTRIBUTE_NORMAL); |
1509 | 0 | if (S_ISDIR(statbuf.st_mode)) |
1510 | 0 | win32filename.dwFileAttributes = Swap32IfBE(RFB_FILE_ATTRIBUTE_DIRECTORY); |
1511 | 0 | win32filename.ftCreationTime.dwLowDateTime = Swap32IfBE(statbuf.st_ctime); /* Intel Order */ |
1512 | 0 | win32filename.ftCreationTime.dwHighDateTime = 0; |
1513 | 0 | win32filename.ftLastAccessTime.dwLowDateTime = Swap32IfBE(statbuf.st_atime); /* Intel Order */ |
1514 | 0 | win32filename.ftLastAccessTime.dwHighDateTime = 0; |
1515 | 0 | win32filename.ftLastWriteTime.dwLowDateTime = Swap32IfBE(statbuf.st_mtime); /* Intel Order */ |
1516 | 0 | win32filename.ftLastWriteTime.dwHighDateTime = 0; |
1517 | 0 | win32filename.nFileSizeLow = Swap32IfBE(statbuf.st_size); /* Intel Order */ |
1518 | 0 | win32filename.nFileSizeHigh = 0; |
1519 | 0 | win32filename.dwReserved0 = 0; |
1520 | 0 | win32filename.dwReserved1 = 0; |
1521 | | |
1522 | | /* If this had the full path, we would need to translate to DOS format ("C:\") */ |
1523 | | /* rfbFilenameTranslate2DOS(cl, retfilename, win32filename.cFileName); */ |
1524 | 0 | strcpy((char *)win32filename.cFileName, direntp->d_name); |
1525 | 0 | #endif |
1526 | | |
1527 | | /* Do not show hidden files (but show how to move up the tree) */ |
1528 | 0 | if ((strcmp((char *)win32filename.cFileName, "..")==0) || (win32filename.cFileName[0]!='.')) |
1529 | 0 | { |
1530 | 0 | nOptLen = sizeof(RFB_FIND_DATA) - MAX_PATH - 14 + strlen((char *)win32filename.cFileName); |
1531 | | /* |
1532 | | rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDirContent: Sending \"%s\"\n", (char *)win32filename.cFileName); |
1533 | | */ |
1534 | 0 | if (rfbSendFileTransferMessage(cl, rfbDirPacket, rfbADirectory, 0, nOptLen, (char *)&win32filename)==FALSE) |
1535 | 0 | { |
1536 | | #ifdef WIN32 |
1537 | | FindClose(findHandle); |
1538 | | #else |
1539 | 0 | closedir(dirp); |
1540 | 0 | #endif |
1541 | 0 | return FALSE; |
1542 | 0 | } |
1543 | 0 | } |
1544 | 0 | } |
1545 | |
|
1546 | | #ifdef WIN32 |
1547 | | if (FindNextFileA(findHandle, &winFindData) == 0) |
1548 | | { |
1549 | | FindClose(findHandle); |
1550 | | findHandle = INVALID_HANDLE_VALUE; |
1551 | | } |
1552 | | #endif |
1553 | 0 | } |
1554 | | #ifdef WIN32 |
1555 | | if (findHandle != INVALID_HANDLE_VALUE) |
1556 | | { |
1557 | | FindClose(findHandle); |
1558 | | } |
1559 | | #else |
1560 | 0 | closedir(dirp); |
1561 | 0 | #endif |
1562 | | /* End of the transfer */ |
1563 | 0 | return rfbSendFileTransferMessage(cl, rfbDirPacket, 0, 0, 0, NULL); |
1564 | 0 | } |
1565 | | |
1566 | | |
1567 | | char *rfbProcessFileTransferReadBuffer(rfbClientPtr cl, uint32_t length) |
1568 | 0 | { |
1569 | 0 | char *buffer=NULL; |
1570 | 0 | int n=0; |
1571 | |
|
1572 | 0 | FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, NULL); |
1573 | | |
1574 | | /* |
1575 | | We later alloc length+1, which might wrap around on 32-bit systems if length equals |
1576 | | 0XFFFFFFFF, i.e. SIZE_MAX for 32-bit systems. On 64-bit systems, a length of 0XFFFFFFFF |
1577 | | will safely be allocated since this check will never trigger and malloc() can digest length+1 |
1578 | | without problems as length is a uint32_t. |
1579 | | We also later pass length to rfbReadExact() that expects a signed int type and |
1580 | | that might wrap on platforms with a 32-bit int type if length is bigger |
1581 | | than 0X7FFFFFFF. |
1582 | | */ |
1583 | 0 | if(length == SIZE_MAX || length > INT_MAX) { |
1584 | 0 | rfbErr("rfbProcessFileTransferReadBuffer: too big file transfer length requested: %u", (unsigned int)length); |
1585 | 0 | rfbCloseClient(cl); |
1586 | 0 | return NULL; |
1587 | 0 | } |
1588 | | |
1589 | 0 | if (length>0) { |
1590 | 0 | buffer=malloc((size_t)length+1); |
1591 | 0 | if (buffer!=NULL) { |
1592 | 0 | if ((n = rfbReadExact(cl, (char *)buffer, length)) <= 0) { |
1593 | 0 | if (n != 0) |
1594 | 0 | rfbLogPerror("rfbProcessFileTransferReadBuffer: read"); |
1595 | 0 | rfbCloseClient(cl); |
1596 | | /* NOTE: don't forget to free(buffer) if you return early! */ |
1597 | 0 | free(buffer); |
1598 | 0 | return NULL; |
1599 | 0 | } |
1600 | | /* Null Terminate */ |
1601 | 0 | buffer[length]=0; |
1602 | 0 | } |
1603 | 0 | } |
1604 | 0 | return buffer; |
1605 | 0 | } |
1606 | | |
1607 | | |
1608 | | rfbBool rfbSendFileTransferChunk(rfbClientPtr cl) |
1609 | 0 | { |
1610 | | /* Allocate buffer for compression */ |
1611 | 0 | char readBuf[sz_rfbBlockSize]; |
1612 | 0 | int bytesRead=0; |
1613 | 0 | int retval=0; |
1614 | 0 | fd_set wfds; |
1615 | 0 | struct timeval tv; |
1616 | 0 | int n; |
1617 | 0 | #ifdef LIBVNCSERVER_HAVE_LIBZ |
1618 | 0 | unsigned char compBuf[sz_rfbBlockSize + 1024]; |
1619 | 0 | unsigned long nMaxCompSize = sizeof(compBuf); |
1620 | 0 | int nRetC = 0; |
1621 | 0 | #endif |
1622 | | |
1623 | | /* |
1624 | | * Don't close the client if we get into this one because |
1625 | | * it is called from many places to service file transfers. |
1626 | | * Note that permitFileTransfer is checked first. |
1627 | | */ |
1628 | 0 | if (cl->screen->permitFileTransfer != TRUE || |
1629 | 0 | (cl->screen->getFileTransferPermission != NULL |
1630 | 0 | && cl->screen->getFileTransferPermission(cl) != TRUE)) { |
1631 | 0 | return TRUE; |
1632 | 0 | } |
1633 | | |
1634 | | /* If not sending, or no file open... Return as if we sent something! */ |
1635 | 0 | if ((cl->fileTransfer.fd!=-1) && (cl->fileTransfer.sending==1)) |
1636 | 0 | { |
1637 | 0 | if(cl->sock == RFB_INVALID_SOCKET) { |
1638 | 0 | errno = EBADF; |
1639 | 0 | return FALSE; |
1640 | 0 | } |
1641 | 0 | FD_ZERO(&wfds); |
1642 | 0 | FD_SET(cl->sock, &wfds); |
1643 | | |
1644 | | /* return immediately */ |
1645 | 0 | tv.tv_sec = 0; |
1646 | 0 | tv.tv_usec = 0; |
1647 | 0 | n = select(cl->sock + 1, NULL, &wfds, NULL, &tv); |
1648 | |
|
1649 | 0 | if (n<0) { |
1650 | | #ifdef WIN32 |
1651 | | errno=WSAGetLastError(); |
1652 | | #endif |
1653 | 0 | rfbLog("rfbSendFileTransferChunk() select failed: %s\n", strerror(errno)); |
1654 | 0 | } |
1655 | | /* We have space on the transmit queue */ |
1656 | 0 | if (n > 0) |
1657 | 0 | { |
1658 | 0 | bytesRead = read(cl->fileTransfer.fd, readBuf, sz_rfbBlockSize); |
1659 | 0 | switch (bytesRead) { |
1660 | 0 | case 0: |
1661 | | /* |
1662 | | rfbLog("rfbSendFileTransferChunk(): End-Of-File Encountered\n"); |
1663 | | */ |
1664 | 0 | retval = rfbSendFileTransferMessage(cl, rfbEndOfFile, 0, 0, 0, NULL); |
1665 | 0 | close(cl->fileTransfer.fd); |
1666 | 0 | cl->fileTransfer.fd = -1; |
1667 | 0 | cl->fileTransfer.sending = 0; |
1668 | 0 | cl->fileTransfer.receiving = 0; |
1669 | 0 | return retval; |
1670 | 0 | case -1: |
1671 | | /* TODO : send an error msg to the client... */ |
1672 | | #ifdef WIN32 |
1673 | | errno=WSAGetLastError(); |
1674 | | #endif |
1675 | 0 | rfbLog("rfbSendFileTransferChunk(): %s\n",strerror(errno)); |
1676 | 0 | retval = rfbSendFileTransferMessage(cl, rfbAbortFileTransfer, 0, 0, 0, NULL); |
1677 | 0 | close(cl->fileTransfer.fd); |
1678 | 0 | cl->fileTransfer.fd = -1; |
1679 | 0 | cl->fileTransfer.sending = 0; |
1680 | 0 | cl->fileTransfer.receiving = 0; |
1681 | 0 | return retval; |
1682 | 0 | default: |
1683 | | /* |
1684 | | rfbLog("rfbSendFileTransferChunk(): Read %d bytes\n", bytesRead); |
1685 | | */ |
1686 | 0 | if (!cl->fileTransfer.compressionEnabled) |
1687 | 0 | return rfbSendFileTransferMessage(cl, rfbFilePacket, 0, 0, bytesRead, readBuf); |
1688 | 0 | else |
1689 | 0 | { |
1690 | 0 | #ifdef LIBVNCSERVER_HAVE_LIBZ |
1691 | 0 | nRetC = compress(compBuf, &nMaxCompSize, (unsigned char *)readBuf, bytesRead); |
1692 | | /* |
1693 | | rfbLog("Compressed the packet from %d -> %d bytes\n", nMaxCompSize, bytesRead); |
1694 | | */ |
1695 | | |
1696 | 0 | if ((nRetC==0) && (nMaxCompSize<bytesRead)) |
1697 | 0 | return rfbSendFileTransferMessage(cl, rfbFilePacket, 0, 1, nMaxCompSize, (char *)compBuf); |
1698 | 0 | else |
1699 | 0 | return rfbSendFileTransferMessage(cl, rfbFilePacket, 0, 0, bytesRead, readBuf); |
1700 | | #else |
1701 | | /* We do not support compression of the data stream */ |
1702 | | return rfbSendFileTransferMessage(cl, rfbFilePacket, 0, 0, bytesRead, readBuf); |
1703 | | #endif |
1704 | 0 | } |
1705 | 0 | } |
1706 | 0 | } |
1707 | 0 | } |
1708 | 0 | return TRUE; |
1709 | 0 | } |
1710 | | |
1711 | | rfbBool rfbProcessFileTransfer(rfbClientPtr cl, uint8_t contentType, uint8_t contentParam, uint32_t size, uint32_t length) |
1712 | 2 | { |
1713 | 2 | char *buffer=NULL, *p=NULL; |
1714 | 2 | int retval=0; |
1715 | 2 | char filename1[MAX_PATH]; |
1716 | 2 | char filename2[MAX_PATH]; |
1717 | 2 | char szFileTime[MAX_PATH]; |
1718 | 2 | struct stat statbuf; |
1719 | 2 | uint32_t sizeHtmp=0; |
1720 | 2 | int n=0; |
1721 | 2 | char timespec[64]; |
1722 | 2 | #ifdef LIBVNCSERVER_HAVE_LIBZ |
1723 | 2 | unsigned char compBuff[sz_rfbBlockSize]; |
1724 | 2 | unsigned long nRawBytes = sz_rfbBlockSize; |
1725 | 2 | int nRet = 0; |
1726 | 2 | #endif |
1727 | | |
1728 | 2 | FILEXFER_ALLOWED_OR_CLOSE_AND_RETURN("", cl, FALSE); |
1729 | | |
1730 | | /* |
1731 | | rfbLog("rfbProcessFileTransfer(%dtype, %dparam, %dsize, %dlen)\n", contentType, contentParam, size, length); |
1732 | | */ |
1733 | |
|
1734 | 0 | switch (contentType) { |
1735 | 0 | case rfbDirContentRequest: |
1736 | 0 | switch (contentParam) { |
1737 | 0 | case rfbRDrivesList: /* Client requests the List of Local Drives */ |
1738 | | /* |
1739 | | rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDrivesList:\n"); |
1740 | | */ |
1741 | | /* Format when filled : "C:\<NULL>D:\<NULL>....Z:\<NULL><NULL> |
1742 | | * |
1743 | | * We replace the "\" char following the drive letter and ":" |
1744 | | * with a char corresponding to the type of drive |
1745 | | * We obtain something like "C:l<NULL>D:c<NULL>....Z:n\<NULL><NULL>" |
1746 | | * Isn't it ugly ? |
1747 | | * DRIVE_FIXED = 'l' (local?) |
1748 | | * DRIVE_REMOVABLE = 'f' (floppy?) |
1749 | | * DRIVE_CDROM = 'c' |
1750 | | * DRIVE_REMOTE = 'n' |
1751 | | */ |
1752 | | |
1753 | | /* in unix, there are no 'drives' (We could list mount points though) |
1754 | | * We fake the root as a "C:" for the Winblows users |
1755 | | */ |
1756 | 0 | filename2[0]='C'; |
1757 | 0 | filename2[1]=':'; |
1758 | 0 | filename2[2]='l'; |
1759 | 0 | filename2[3]=0; |
1760 | 0 | filename2[4]=0; |
1761 | 0 | retval = rfbSendFileTransferMessage(cl, rfbDirPacket, rfbADrivesList, 0, 5, filename2); |
1762 | 0 | return retval; |
1763 | 0 | break; |
1764 | 0 | case rfbRDirContent: /* Client requests the content of a directory */ |
1765 | | /* |
1766 | | rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDirContent\n"); |
1767 | | */ |
1768 | 0 | if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE; |
1769 | 0 | retval = rfbSendDirContent(cl, length, buffer); |
1770 | 0 | free(buffer); |
1771 | 0 | return retval; |
1772 | 0 | } |
1773 | 0 | break; |
1774 | | |
1775 | 0 | case rfbDirPacket: |
1776 | 0 | rfbLog("rfbProcessFileTransfer() rfbDirPacket\n"); |
1777 | 0 | break; |
1778 | 0 | case rfbFileAcceptHeader: |
1779 | 0 | rfbLog("rfbProcessFileTransfer() rfbFileAcceptHeader\n"); |
1780 | 0 | break; |
1781 | 0 | case rfbCommandReturn: |
1782 | 0 | rfbLog("rfbProcessFileTransfer() rfbCommandReturn\n"); |
1783 | 0 | break; |
1784 | 0 | case rfbFileChecksums: |
1785 | | /* Destination file already exists - the viewer sends the checksums */ |
1786 | 0 | rfbLog("rfbProcessFileTransfer() rfbFileChecksums\n"); |
1787 | 0 | break; |
1788 | 0 | case rfbFileTransferAccess: |
1789 | 0 | rfbLog("rfbProcessFileTransfer() rfbFileTransferAccess\n"); |
1790 | 0 | break; |
1791 | | |
1792 | | /* |
1793 | | * sending from the server to the viewer |
1794 | | */ |
1795 | | |
1796 | 0 | case rfbFileTransferRequest: |
1797 | | /* |
1798 | | rfbLog("rfbProcessFileTransfer() rfbFileTransferRequest:\n"); |
1799 | | */ |
1800 | | /* add some space to the end of the buffer as we will be adding a timespec to it */ |
1801 | 0 | if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE; |
1802 | | /* The client requests a File */ |
1803 | 0 | if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1))) |
1804 | 0 | goto fail; |
1805 | 0 | cl->fileTransfer.fd=open(filename1, O_RDONLY, 0744); |
1806 | | |
1807 | | /* |
1808 | | */ |
1809 | 0 | if (DB) rfbLog("rfbProcessFileTransfer() rfbFileTransferRequest(\"%s\"->\"%s\") Open: %s fd=%d\n", buffer, filename1, (cl->fileTransfer.fd==-1?"Failed":"Success"), cl->fileTransfer.fd); |
1810 | | |
1811 | 0 | if (cl->fileTransfer.fd!=-1) { |
1812 | 0 | if (fstat(cl->fileTransfer.fd, &statbuf)!=0) { |
1813 | 0 | close(cl->fileTransfer.fd); |
1814 | 0 | cl->fileTransfer.fd=-1; |
1815 | 0 | } |
1816 | 0 | else |
1817 | 0 | { |
1818 | | /* Add the File Time Stamp to the filename */ |
1819 | 0 | strftime(timespec, sizeof(timespec), "%m/%d/%Y %H:%M",gmtime(&statbuf.st_ctime)); |
1820 | 0 | buffer=realloc(buffer, length + strlen(timespec) + 2); /* comma, and Null term */ |
1821 | 0 | if (buffer==NULL) { |
1822 | 0 | rfbLog("rfbProcessFileTransfer() rfbFileTransferRequest: Failed to malloc %d bytes\n", length + strlen(timespec) + 2); |
1823 | 0 | return FALSE; |
1824 | 0 | } |
1825 | 0 | strcat(buffer,","); |
1826 | 0 | strcat(buffer, timespec); |
1827 | 0 | length = strlen(buffer); |
1828 | 0 | if (DB) rfbLog("rfbProcessFileTransfer() buffer is now: \"%s\"\n", buffer); |
1829 | 0 | } |
1830 | 0 | } else { |
1831 | 0 | statbuf.st_size = 0; |
1832 | 0 | } |
1833 | | |
1834 | | /* The viewer supports compression if size==1 */ |
1835 | 0 | cl->fileTransfer.compressionEnabled = (size==1); |
1836 | | |
1837 | | /* |
1838 | | rfbLog("rfbProcessFileTransfer() rfbFileTransferRequest(\"%s\"->\"%s\")%s\n", buffer, filename1, (size==1?" <Compression Enabled>":"")); |
1839 | | */ |
1840 | | |
1841 | | /* File Size in bytes, 0xFFFFFFFF (-1) means error */ |
1842 | 0 | retval = rfbSendFileTransferMessage(cl, rfbFileHeader, 0, (cl->fileTransfer.fd==-1 ? -1 : statbuf.st_size), length, buffer); |
1843 | |
|
1844 | 0 | if (cl->fileTransfer.fd==-1) |
1845 | 0 | { |
1846 | 0 | free(buffer); |
1847 | 0 | return retval; |
1848 | 0 | } |
1849 | | /* setup filetransfer stuff */ |
1850 | 0 | cl->fileTransfer.fileSize = statbuf.st_size; |
1851 | 0 | cl->fileTransfer.numPackets = statbuf.st_size / sz_rfbBlockSize; |
1852 | 0 | cl->fileTransfer.receiving = 0; |
1853 | 0 | cl->fileTransfer.sending = 0; /* set when we receive a rfbFileHeader: */ |
1854 | | |
1855 | | /* TODO: finish 64-bit file size support */ |
1856 | 0 | sizeHtmp = 0; |
1857 | 0 | LOCK(cl->sendMutex); |
1858 | 0 | if (rfbWriteExact(cl, (char *)&sizeHtmp, 4) < 0) { |
1859 | 0 | rfbLogPerror("rfbProcessFileTransfer: write"); |
1860 | 0 | rfbCloseClient(cl); |
1861 | 0 | UNLOCK(cl->sendMutex); |
1862 | 0 | free(buffer); |
1863 | 0 | return FALSE; |
1864 | 0 | } |
1865 | 0 | UNLOCK(cl->sendMutex); |
1866 | 0 | break; |
1867 | | |
1868 | 0 | case rfbFileHeader: |
1869 | | /* Destination file (viewer side) is ready for reception (size > 0) or not (size = -1) */ |
1870 | 0 | if (size==-1) { |
1871 | 0 | rfbLog("rfbProcessFileTransfer() rfbFileHeader (error, aborting)\n"); |
1872 | 0 | close(cl->fileTransfer.fd); |
1873 | 0 | cl->fileTransfer.fd=-1; |
1874 | 0 | return TRUE; |
1875 | 0 | } |
1876 | | |
1877 | | /* |
1878 | | rfbLog("rfbProcessFileTransfer() rfbFileHeader (%d bytes of a file)\n", size); |
1879 | | */ |
1880 | | |
1881 | | /* Starts the transfer! */ |
1882 | 0 | cl->fileTransfer.sending=1; |
1883 | 0 | return rfbSendFileTransferChunk(cl); |
1884 | 0 | break; |
1885 | | |
1886 | | |
1887 | | /* |
1888 | | * sending from the viewer to the server |
1889 | | */ |
1890 | | |
1891 | 0 | case rfbFileTransferOffer: |
1892 | | /* client is sending a file to us */ |
1893 | | /* buffer contains full path name (plus FileTime) */ |
1894 | | /* size contains size of the file */ |
1895 | | /* |
1896 | | rfbLog("rfbProcessFileTransfer() rfbFileTransferOffer:\n"); |
1897 | | */ |
1898 | 0 | if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE; |
1899 | | |
1900 | | /* Parse the FileTime */ |
1901 | 0 | p = strrchr(buffer, ','); |
1902 | 0 | if (p!=NULL) { |
1903 | 0 | *p = '\0'; |
1904 | 0 | strncpy(szFileTime, p+1, sizeof(szFileTime)); |
1905 | 0 | szFileTime[sizeof(szFileTime)-1] = '\x00'; /* ensure NULL terminating byte is present, even if copy overflowed */ |
1906 | 0 | } else |
1907 | 0 | szFileTime[0]=0; |
1908 | | |
1909 | | |
1910 | | |
1911 | | /* Need to read in sizeHtmp */ |
1912 | 0 | if ((n = rfbReadExact(cl, (char *)&sizeHtmp, 4)) <= 0) { |
1913 | 0 | if (n != 0) |
1914 | 0 | rfbLogPerror("rfbProcessFileTransfer: read sizeHtmp"); |
1915 | 0 | rfbCloseClient(cl); |
1916 | | /* NOTE: don't forget to free(buffer) if you return early! */ |
1917 | 0 | free(buffer); |
1918 | 0 | return FALSE; |
1919 | 0 | } |
1920 | 0 | sizeHtmp = Swap32IfLE(sizeHtmp); |
1921 | | |
1922 | 0 | if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1))) |
1923 | 0 | goto fail; |
1924 | | |
1925 | | /* If the file exists... We can send a rfbFileChecksums back to the client before we send an rfbFileAcceptHeader */ |
1926 | | /* TODO: Delta Transfer */ |
1927 | | |
1928 | 0 | cl->fileTransfer.fd=open(filename1, O_CREAT|O_WRONLY|O_TRUNC, 0744); |
1929 | 0 | if (DB) rfbLog("rfbProcessFileTransfer() rfbFileTransferOffer(\"%s\"->\"%s\") %s %s fd=%d\n", buffer, filename1, (cl->fileTransfer.fd==-1?"Failed":"Success"), (cl->fileTransfer.fd==-1?strerror(errno):""), cl->fileTransfer.fd); |
1930 | | /* |
1931 | | */ |
1932 | | |
1933 | | /* File Size in bytes, 0xFFFFFFFF (-1) means error */ |
1934 | 0 | retval = rfbSendFileTransferMessage(cl, rfbFileAcceptHeader, 0, (cl->fileTransfer.fd==-1 ? -1 : 0), length, buffer); |
1935 | 0 | if (cl->fileTransfer.fd==-1) { |
1936 | 0 | free(buffer); |
1937 | 0 | return retval; |
1938 | 0 | } |
1939 | | |
1940 | | /* setup filetransfer stuff */ |
1941 | 0 | cl->fileTransfer.fileSize = size; |
1942 | 0 | cl->fileTransfer.numPackets = size / sz_rfbBlockSize; |
1943 | 0 | cl->fileTransfer.receiving = 1; |
1944 | 0 | cl->fileTransfer.sending = 0; |
1945 | 0 | break; |
1946 | | |
1947 | 0 | case rfbFilePacket: |
1948 | | /* |
1949 | | rfbLog("rfbProcessFileTransfer() rfbFilePacket:\n"); |
1950 | | */ |
1951 | 0 | if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE; |
1952 | 0 | if (cl->fileTransfer.fd!=-1) { |
1953 | | /* buffer contains the contents of the file */ |
1954 | 0 | if (size==0) |
1955 | 0 | retval=write(cl->fileTransfer.fd, buffer, length); |
1956 | 0 | else |
1957 | 0 | { |
1958 | 0 | #ifdef LIBVNCSERVER_HAVE_LIBZ |
1959 | | /* compressed packet */ |
1960 | 0 | nRet = uncompress(compBuff,&nRawBytes,(const unsigned char*)buffer, length); |
1961 | 0 | if(nRet == Z_OK) |
1962 | 0 | retval=write(cl->fileTransfer.fd, (char*)compBuff, nRawBytes); |
1963 | 0 | else |
1964 | 0 | retval = -1; |
1965 | | #else |
1966 | | /* Write the file out as received... */ |
1967 | | retval=write(cl->fileTransfer.fd, buffer, length); |
1968 | | #endif |
1969 | 0 | } |
1970 | 0 | if (retval==-1) |
1971 | 0 | { |
1972 | 0 | close(cl->fileTransfer.fd); |
1973 | 0 | cl->fileTransfer.fd=-1; |
1974 | 0 | cl->fileTransfer.sending = 0; |
1975 | 0 | cl->fileTransfer.receiving = 0; |
1976 | 0 | } |
1977 | 0 | } |
1978 | 0 | break; |
1979 | | |
1980 | 0 | case rfbEndOfFile: |
1981 | 0 | if (DB) rfbLog("rfbProcessFileTransfer() rfbEndOfFile\n"); |
1982 | | /* |
1983 | | */ |
1984 | 0 | if (cl->fileTransfer.fd!=-1) |
1985 | 0 | close(cl->fileTransfer.fd); |
1986 | 0 | cl->fileTransfer.fd=-1; |
1987 | 0 | cl->fileTransfer.sending = 0; |
1988 | 0 | cl->fileTransfer.receiving = 0; |
1989 | 0 | break; |
1990 | | |
1991 | 0 | case rfbAbortFileTransfer: |
1992 | 0 | if (DB) rfbLog("rfbProcessFileTransfer() rfbAbortFileTransfer\n"); |
1993 | | /* |
1994 | | */ |
1995 | 0 | if (cl->fileTransfer.fd!=-1) |
1996 | 0 | { |
1997 | 0 | close(cl->fileTransfer.fd); |
1998 | 0 | cl->fileTransfer.fd=-1; |
1999 | 0 | cl->fileTransfer.sending = 0; |
2000 | 0 | cl->fileTransfer.receiving = 0; |
2001 | 0 | } |
2002 | 0 | else |
2003 | 0 | { |
2004 | | /* We use this message for FileTransfer rights (<=RC18 versions) |
2005 | | * The client asks for FileTransfer permission |
2006 | | */ |
2007 | 0 | if (contentParam == 0) |
2008 | 0 | { |
2009 | 0 | rfbLog("rfbProcessFileTransfer() File Transfer Permission DENIED! (Client Version <=RC18)\n"); |
2010 | | /* Old method for FileTransfer handshake perimssion (<=RC18) (Deny it)*/ |
2011 | 0 | return rfbSendFileTransferMessage(cl, rfbAbortFileTransfer, 0, -1, 0, ""); |
2012 | 0 | } |
2013 | | /* New method is allowed */ |
2014 | 0 | if (cl->screen->getFileTransferPermission!=NULL) |
2015 | 0 | { |
2016 | 0 | if (cl->screen->getFileTransferPermission(cl)==TRUE) |
2017 | 0 | { |
2018 | 0 | rfbLog("rfbProcessFileTransfer() File Transfer Permission Granted!\n"); |
2019 | 0 | return rfbSendFileTransferMessage(cl, rfbFileTransferAccess, 0, 1 , 0, ""); /* Permit */ |
2020 | 0 | } |
2021 | 0 | else |
2022 | 0 | { |
2023 | 0 | rfbLog("rfbProcessFileTransfer() File Transfer Permission DENIED!\n"); |
2024 | 0 | return rfbSendFileTransferMessage(cl, rfbFileTransferAccess, 0, -1 , 0, ""); /* Deny */ |
2025 | 0 | } |
2026 | 0 | } |
2027 | 0 | else |
2028 | 0 | { |
2029 | 0 | if (cl->screen->permitFileTransfer) |
2030 | 0 | { |
2031 | 0 | rfbLog("rfbProcessFileTransfer() File Transfer Permission Granted!\n"); |
2032 | 0 | return rfbSendFileTransferMessage(cl, rfbFileTransferAccess, 0, 1 , 0, ""); /* Permit */ |
2033 | 0 | } |
2034 | 0 | else |
2035 | 0 | { |
2036 | 0 | rfbLog("rfbProcessFileTransfer() File Transfer Permission DENIED by default!\n"); |
2037 | 0 | return rfbSendFileTransferMessage(cl, rfbFileTransferAccess, 0, -1 , 0, ""); /* DEFAULT: DENY (for security) */ |
2038 | 0 | } |
2039 | | |
2040 | 0 | } |
2041 | 0 | } |
2042 | 0 | break; |
2043 | | |
2044 | | |
2045 | 0 | case rfbCommand: |
2046 | | /* |
2047 | | rfbLog("rfbProcessFileTransfer() rfbCommand:\n"); |
2048 | | */ |
2049 | 0 | if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE; |
2050 | 0 | switch (contentParam) { |
2051 | 0 | case rfbCDirCreate: /* Client requests the creation of a directory */ |
2052 | 0 | if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1))) |
2053 | 0 | goto fail; |
2054 | 0 | retval = mkdir(filename1, 0755); |
2055 | 0 | if (DB) rfbLog("rfbProcessFileTransfer() rfbCommand: rfbCDirCreate(\"%s\"->\"%s\") %s\n", buffer, filename1, (retval==-1?"Failed":"Success")); |
2056 | | /* |
2057 | | */ |
2058 | 0 | retval = rfbSendFileTransferMessage(cl, rfbCommandReturn, rfbADirCreate, retval, length, buffer); |
2059 | 0 | free(buffer); |
2060 | 0 | return retval; |
2061 | 0 | case rfbCFileDelete: /* Client requests the deletion of a file */ |
2062 | 0 | if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1))) |
2063 | 0 | goto fail; |
2064 | 0 | if (stat(filename1,&statbuf)==0) |
2065 | 0 | { |
2066 | 0 | if (S_ISDIR(statbuf.st_mode)) |
2067 | 0 | retval = rmdir(filename1); |
2068 | 0 | else |
2069 | 0 | retval = unlink(filename1); |
2070 | 0 | } |
2071 | 0 | else retval=-1; |
2072 | 0 | retval = rfbSendFileTransferMessage(cl, rfbCommandReturn, rfbAFileDelete, retval, length, buffer); |
2073 | 0 | free(buffer); |
2074 | 0 | return retval; |
2075 | 0 | case rfbCFileRename: /* Client requests the Renaming of a file/directory */ |
2076 | 0 | p = strrchr(buffer, '*'); |
2077 | 0 | if (p != NULL) |
2078 | 0 | { |
2079 | | /* Split into 2 filenames ('*' is a seperator) */ |
2080 | 0 | *p = '\0'; |
2081 | 0 | if (!rfbFilenameTranslate2UNIX(cl, buffer, filename1, sizeof(filename1))) |
2082 | 0 | goto fail; |
2083 | 0 | if (!rfbFilenameTranslate2UNIX(cl, p+1, filename2, sizeof(filename2))) |
2084 | 0 | goto fail; |
2085 | 0 | retval = rename(filename1,filename2); |
2086 | 0 | if (DB) rfbLog("rfbProcessFileTransfer() rfbCommand: rfbCFileRename(\"%s\"->\"%s\" -->> \"%s\"->\"%s\") %s\n", buffer, filename1, p+1, filename2, (retval==-1?"Failed":"Success")); |
2087 | | /* |
2088 | | */ |
2089 | | /* Restore the buffer so the reply is good */ |
2090 | 0 | *p = '*'; |
2091 | 0 | retval = rfbSendFileTransferMessage(cl, rfbCommandReturn, rfbAFileRename, retval, length, buffer); |
2092 | 0 | free(buffer); |
2093 | 0 | return retval; |
2094 | 0 | } |
2095 | 0 | break; |
2096 | 0 | } |
2097 | | |
2098 | 0 | break; |
2099 | 0 | } |
2100 | | |
2101 | | /* NOTE: don't forget to free(buffer) if you return early! */ |
2102 | 0 | free(buffer); |
2103 | 0 | return TRUE; |
2104 | | |
2105 | 0 | fail: |
2106 | 0 | free(buffer); |
2107 | 0 | return FALSE; |
2108 | 0 | } |
2109 | | |
2110 | | #ifdef LIBVNCSERVER_HAVE_LIBZ |
2111 | | static rfbBool |
2112 | 0 | rfbSendExtendedClipboardCapability(rfbClientPtr cl) { |
2113 | 0 | char buf[16] = { |
2114 | 0 | 0x03, 0x00, 0x00, 0x00, |
2115 | 0 | 0xFF, 0xFF, 0xFF, 0xF8, /* -8 */ |
2116 | 0 | 0x17, 0x00, 0x00, 0x01, /* text, request, peek, provide */ |
2117 | 0 | 0x00, 0x10, 0x00, 0x00, /* max size is 1MiB */ |
2118 | 0 | }; |
2119 | 0 | if (rfbWriteExact(cl, buf, sizeof(buf)) < 0) { |
2120 | 0 | rfbLogPerror("rfbSendExtendedClipboardCapability: write"); |
2121 | 0 | rfbCloseClient(cl); |
2122 | 0 | return FALSE; |
2123 | 0 | } |
2124 | 0 | rfbStatRecordMessageSent(cl, rfbServerCutText, sizeof(buf), sizeof(buf)); |
2125 | 0 | return TRUE; |
2126 | 0 | } |
2127 | | |
2128 | | static rfbBool |
2129 | 0 | rfbSendExtendedClipboardNotify(rfbClientPtr cl) { |
2130 | 0 | char buf[12] = { |
2131 | 0 | 0x03, 0x00, 0x00, 0x00, |
2132 | 0 | 0xFF, 0xFF, 0xFF, 0xFC, /* -4 */ |
2133 | 0 | 0x08, 0x00, 0x00, 0x01, /* only text */ |
2134 | 0 | }; |
2135 | 0 | if (rfbWriteExact(cl, buf, sizeof(buf)) < 0) { |
2136 | 0 | rfbLogPerror("rfbSendExtendedClipboardNotify: write"); |
2137 | 0 | rfbCloseClient(cl); |
2138 | 0 | return FALSE; |
2139 | 0 | } |
2140 | 0 | rfbStatRecordMessageSent(cl, rfbServerCutText, sizeof(buf), sizeof(buf)); |
2141 | 0 | return TRUE; |
2142 | 0 | } |
2143 | | |
2144 | | static rfbBool |
2145 | 0 | rfbSendExtendedServerCutTextData(rfbClientPtr cl, const char *data, int len) { |
2146 | 0 | int i; |
2147 | 0 | unsigned long size; |
2148 | 0 | uint32_t tmpInt; |
2149 | 0 | char *bufBeforeZlib; |
2150 | 0 | char *bufAfterZlib; |
2151 | 0 | bufBeforeZlib = (char *)malloc(len + 4); |
2152 | 0 | if (bufBeforeZlib == NULL) { |
2153 | 0 | rfbLogPerror("rfbSendExtendedClipboardCapability: failed to allocate memory"); |
2154 | 0 | rfbCloseClient(cl); |
2155 | 0 | return FALSE; |
2156 | 0 | } |
2157 | 0 | tmpInt = Swap32IfLE(len); |
2158 | 0 | memcpy(bufBeforeZlib, &tmpInt, 4); |
2159 | 0 | memcpy(bufBeforeZlib + 4, data, len); |
2160 | 0 | size = compressBound(len + 4); |
2161 | 0 | bufAfterZlib = (char *)malloc(12 + size); |
2162 | 0 | if (bufAfterZlib == NULL) { |
2163 | 0 | rfbLogPerror("rfbSendExtendedClipboardCapability: failed to allocate memory"); |
2164 | 0 | free(bufBeforeZlib); |
2165 | 0 | rfbCloseClient(cl); |
2166 | 0 | return FALSE; |
2167 | 0 | } |
2168 | 0 | if (compress((unsigned char *)bufAfterZlib + 12, &size, (unsigned char *)bufBeforeZlib, len + 4) != Z_OK) { |
2169 | 0 | rfbLogPerror("rfbSendExtendedClipboardCapability: zlib deflation error"); |
2170 | 0 | free(bufBeforeZlib); |
2171 | 0 | free(bufAfterZlib); |
2172 | 0 | rfbCloseClient(cl); |
2173 | 0 | return FALSE; |
2174 | 0 | } |
2175 | 0 | bufAfterZlib[0] = 3; |
2176 | 0 | bufAfterZlib[1] = 0; |
2177 | 0 | bufAfterZlib[2] = 0; |
2178 | 0 | bufAfterZlib[3] = 0; |
2179 | 0 | tmpInt = Swap32IfLE(-(4 + size)); |
2180 | 0 | memcpy(bufAfterZlib + 4, &tmpInt, 4); |
2181 | 0 | tmpInt = Swap32IfLE(rfbExtendedClipboard_Provide | rfbExtendedClipboard_Text); |
2182 | 0 | memcpy(bufAfterZlib + 8, &tmpInt, 4); |
2183 | 0 | if (rfbWriteExact(cl, bufAfterZlib, 12 + size) < 0) { |
2184 | 0 | rfbLogPerror("rfbSendExtendedClipboardCapability: write"); |
2185 | 0 | free(bufBeforeZlib); |
2186 | 0 | free(bufAfterZlib); |
2187 | 0 | rfbCloseClient(cl); |
2188 | 0 | return FALSE; |
2189 | 0 | } |
2190 | 0 | rfbStatRecordMessageSent(cl, rfbServerCutText, 12 + size, 12 + size); |
2191 | 0 | free(bufBeforeZlib); |
2192 | 0 | free(bufAfterZlib); |
2193 | 0 | return TRUE; |
2194 | 0 | } |
2195 | | |
2196 | | static int |
2197 | 0 | rfbProcessExtendedServerCutTextData(rfbClientPtr cl, uint32_t flags, const char *data, int len) { |
2198 | 0 | int i; |
2199 | 0 | uint32_t size; |
2200 | 0 | char *buf = NULL; |
2201 | 0 | z_stream stream; |
2202 | 0 | stream.zalloc = NULL; |
2203 | 0 | stream.zfree = NULL; |
2204 | 0 | stream.opaque = NULL; |
2205 | 0 | stream.avail_in = 0; |
2206 | 0 | stream.next_in = NULL; |
2207 | 0 | if (inflateInit(&stream) != Z_OK) { |
2208 | 0 | rfbLogPerror("rfbProcessExtendedServerCutTextData: zlib stream initialization error"); |
2209 | 0 | rfbCloseClient(cl); |
2210 | 0 | return FALSE; |
2211 | 0 | } |
2212 | 0 | stream.avail_in = len; |
2213 | 0 | stream.next_in = data; |
2214 | 0 | for (i = 0; i < 16; i++) { |
2215 | 0 | if (!(flags & (1 << i))) { |
2216 | 0 | continue; |
2217 | 0 | } |
2218 | 0 | stream.avail_out = 4; |
2219 | 0 | stream.next_out = (unsigned char *)&size; |
2220 | 0 | int err = inflate(&stream, Z_NO_FLUSH); |
2221 | 0 | if (err != Z_OK) { |
2222 | 0 | rfbLogPerror("rfbProcessExtendedServerCutTextData: zlib inflation error"); |
2223 | 0 | if (buf != NULL) { |
2224 | 0 | free(buf); |
2225 | 0 | } |
2226 | 0 | inflateEnd(&stream); |
2227 | 0 | rfbCloseClient(cl); |
2228 | 0 | return FALSE; |
2229 | 0 | } |
2230 | 0 | size = Swap32IfLE(size); |
2231 | 0 | if (buf != NULL) { |
2232 | 0 | free(buf); |
2233 | 0 | buf = NULL; |
2234 | 0 | } |
2235 | 0 | if (size > (1 << 20)) { |
2236 | 0 | rfbLog("rfbProcessExtendedServerCutTextData: too big requested: %u B > 1 MB\n", (unsigned int)size); |
2237 | 0 | inflateEnd(&stream); |
2238 | 0 | rfbCloseClient(cl); |
2239 | 0 | return FALSE; |
2240 | 0 | } |
2241 | 0 | buf = (char *)malloc(size); |
2242 | 0 | if (buf == NULL) { |
2243 | 0 | rfbLogPerror("rfbProcessExtendedServerCutTextData: failed to allocate memory"); |
2244 | 0 | inflateEnd(&stream); |
2245 | 0 | rfbCloseClient(cl); |
2246 | 0 | return FALSE; |
2247 | 0 | } |
2248 | 0 | stream.avail_out = size; |
2249 | 0 | stream.next_out = (unsigned char *)buf; |
2250 | 0 | err = inflate(&stream, Z_NO_FLUSH); |
2251 | 0 | if (err != Z_OK && err != Z_STREAM_END) { |
2252 | 0 | rfbLogPerror("rfbProcessExtendedServerCutTextData: zlib inflation error"); |
2253 | 0 | free(buf); |
2254 | 0 | inflateEnd(&stream); |
2255 | 0 | rfbCloseClient(cl); |
2256 | 0 | return FALSE; |
2257 | 0 | } |
2258 | 0 | if (i == 0) { |
2259 | | /* text */ |
2260 | 0 | if (!cl->viewOnly && cl->screen->setXCutTextUTF8) { |
2261 | 0 | cl->screen->setXCutTextUTF8(buf, size, cl); |
2262 | 0 | } |
2263 | 0 | } |
2264 | 0 | } |
2265 | 0 | free(buf); |
2266 | 0 | inflateEnd(&stream); |
2267 | 0 | return TRUE; |
2268 | 0 | } |
2269 | | #endif |
2270 | | |
2271 | | /* |
2272 | | * rfbProcessClientNormalMessage is called when the client has sent a normal |
2273 | | * protocol message. |
2274 | | */ |
2275 | | |
2276 | | static void |
2277 | | rfbProcessClientNormalMessage(rfbClientPtr cl) |
2278 | 73.7k | { |
2279 | 73.7k | int n=0; |
2280 | 73.7k | rfbClientToServerMsg msg; |
2281 | 73.7k | char *str; |
2282 | 73.7k | int i; |
2283 | 73.7k | uint32_t enc=0; |
2284 | 73.7k | uint32_t lastPreferredEncoding = -1; |
2285 | 73.7k | char encBuf[64]; |
2286 | 73.7k | char encBuf2[64]; |
2287 | 73.7k | rfbExtDesktopScreen *extDesktopScreens; |
2288 | 73.7k | rfbClientIteratorPtr iterator; |
2289 | 73.7k | rfbClientPtr clp; |
2290 | 73.7k | #ifdef LIBVNCSERVER_HAVE_LIBZ |
2291 | 73.7k | rfbBool isExtendedCutText = FALSE; |
2292 | 73.7k | uint32_t extClipboardFlags; |
2293 | 73.7k | int extClipboardFormats = 0; |
2294 | 73.7k | #endif |
2295 | | |
2296 | 73.7k | if ((n = rfbReadExact(cl, (char *)&msg, 1)) <= 0) { |
2297 | 1.30k | if (n != 0) |
2298 | 0 | rfbLogPerror("rfbProcessClientNormalMessage: read"); |
2299 | 1.30k | rfbCloseClient(cl); |
2300 | 1.30k | return; |
2301 | 1.30k | } |
2302 | | |
2303 | 72.4k | switch (msg.type) { |
2304 | | |
2305 | 10.4k | case rfbSetPixelFormat: |
2306 | | |
2307 | 10.4k | if ((n = rfbReadExact(cl, ((char *)&msg) + 1, |
2308 | 10.4k | sz_rfbSetPixelFormatMsg - 1)) <= 0) { |
2309 | 31 | if (n != 0) |
2310 | 0 | rfbLogPerror("rfbProcessClientNormalMessage: read"); |
2311 | 31 | rfbCloseClient(cl); |
2312 | 31 | return; |
2313 | 31 | } |
2314 | | |
2315 | 10.4k | cl->format.bitsPerPixel = msg.spf.format.bitsPerPixel; |
2316 | 10.4k | cl->format.depth = msg.spf.format.depth; |
2317 | 10.4k | cl->format.bigEndian = (msg.spf.format.bigEndian ? TRUE : FALSE); |
2318 | 10.4k | cl->format.trueColour = (msg.spf.format.trueColour ? TRUE : FALSE); |
2319 | 10.4k | cl->format.redMax = Swap16IfLE(msg.spf.format.redMax); |
2320 | 10.4k | cl->format.greenMax = Swap16IfLE(msg.spf.format.greenMax); |
2321 | 10.4k | cl->format.blueMax = Swap16IfLE(msg.spf.format.blueMax); |
2322 | 10.4k | cl->format.redShift = msg.spf.format.redShift; |
2323 | 10.4k | cl->format.greenShift = msg.spf.format.greenShift; |
2324 | 10.4k | cl->format.blueShift = msg.spf.format.blueShift; |
2325 | | |
2326 | 10.4k | cl->readyForSetColourMapEntries = TRUE; |
2327 | 10.4k | cl->screen->setTranslateFunction(cl); |
2328 | | |
2329 | 10.4k | rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetPixelFormatMsg, sz_rfbSetPixelFormatMsg); |
2330 | | |
2331 | 10.4k | return; |
2332 | | |
2333 | | |
2334 | 12 | case rfbFixColourMapEntries: |
2335 | 12 | if ((n = rfbReadExact(cl, ((char *)&msg) + 1, |
2336 | 12 | sz_rfbFixColourMapEntriesMsg - 1)) <= 0) { |
2337 | 9 | if (n != 0) |
2338 | 0 | rfbLogPerror("rfbProcessClientNormalMessage: read"); |
2339 | 9 | rfbCloseClient(cl); |
2340 | 9 | return; |
2341 | 9 | } |
2342 | 3 | rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetPixelFormatMsg, sz_rfbSetPixelFormatMsg); |
2343 | 3 | rfbLog("rfbProcessClientNormalMessage: %s", |
2344 | 3 | "FixColourMapEntries unsupported\n"); |
2345 | 3 | rfbCloseClient(cl); |
2346 | 3 | return; |
2347 | | |
2348 | | |
2349 | | /* NOTE: Some clients send us a set of encodings (ie: PointerPos) designed to enable/disable features... |
2350 | | * We may want to look into this... |
2351 | | * Example: |
2352 | | * case rfbEncodingXCursor: |
2353 | | * cl->enableCursorShapeUpdates = TRUE; |
2354 | | * |
2355 | | * Currently: cl->enableCursorShapeUpdates can *never* be turned off... |
2356 | | */ |
2357 | 6.90k | case rfbSetEncodings: |
2358 | 6.90k | { |
2359 | | |
2360 | 6.90k | if ((n = rfbReadExact(cl, ((char *)&msg) + 1, |
2361 | 6.90k | sz_rfbSetEncodingsMsg - 1)) <= 0) { |
2362 | 25 | if (n != 0) |
2363 | 0 | rfbLogPerror("rfbProcessClientNormalMessage: read"); |
2364 | 25 | rfbCloseClient(cl); |
2365 | 25 | return; |
2366 | 25 | } |
2367 | | |
2368 | 6.88k | msg.se.nEncodings = Swap16IfLE(msg.se.nEncodings); |
2369 | | |
2370 | 6.88k | rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetEncodingsMsg+(msg.se.nEncodings*4),sz_rfbSetEncodingsMsg+(msg.se.nEncodings*4)); |
2371 | | |
2372 | | /* |
2373 | | * UltraVNC Client has the ability to adapt to changing network environments |
2374 | | * So, let's give it a change to tell us what it wants now! |
2375 | | */ |
2376 | 6.88k | if (cl->preferredEncoding!=-1) |
2377 | 5.93k | lastPreferredEncoding = cl->preferredEncoding; |
2378 | | |
2379 | | /* Reset all flags to defaults (allows us to switch between PointerPos and Server Drawn Cursors) */ |
2380 | 6.88k | cl->preferredEncoding=-1; |
2381 | 6.88k | cl->useCopyRect = FALSE; |
2382 | 6.88k | cl->useNewFBSize = FALSE; |
2383 | 6.88k | cl->useExtDesktopSize = FALSE; |
2384 | 6.88k | cl->cursorWasChanged = FALSE; |
2385 | 6.88k | cl->useRichCursorEncoding = FALSE; |
2386 | 6.88k | cl->enableCursorPosUpdates = FALSE; |
2387 | 6.88k | cl->enableCursorShapeUpdates = FALSE; |
2388 | 6.88k | cl->enableLastRectEncoding = FALSE; |
2389 | 6.88k | cl->enableKeyboardLedState = FALSE; |
2390 | 6.88k | cl->enableSupportedMessages = FALSE; |
2391 | 6.88k | cl->enableSupportedEncodings = FALSE; |
2392 | 6.88k | cl->enableServerIdentity = FALSE; |
2393 | 6.88k | #if defined(LIBVNCSERVER_HAVE_LIBZ) || defined(LIBVNCSERVER_HAVE_LIBPNG) |
2394 | 6.88k | cl->tightQualityLevel = -1; |
2395 | | #ifdef LIBVNCSERVER_HAVE_LIBJPEG |
2396 | | cl->tightCompressLevel = TIGHT_DEFAULT_COMPRESSION; |
2397 | | cl->turboSubsampLevel = TURBO_DEFAULT_SUBSAMP; |
2398 | | cl->turboQualityLevel = -1; |
2399 | | #endif |
2400 | 6.88k | #endif |
2401 | | |
2402 | | |
2403 | 37.3k | for (i = 0; i < msg.se.nEncodings; i++) { |
2404 | 31.1k | if ((n = rfbReadExact(cl, (char *)&enc, 4)) <= 0) { |
2405 | 636 | if (n != 0) |
2406 | 0 | rfbLogPerror("rfbProcessClientNormalMessage: read"); |
2407 | 636 | rfbCloseClient(cl); |
2408 | 636 | return; |
2409 | 636 | } |
2410 | 30.4k | enc = Swap32IfLE(enc); |
2411 | | |
2412 | 30.4k | switch (enc) { |
2413 | | |
2414 | 210 | case rfbEncodingCopyRect: |
2415 | 210 | cl->useCopyRect = TRUE; |
2416 | 210 | break; |
2417 | 522 | case rfbEncodingRaw: |
2418 | 771 | case rfbEncodingRRE: |
2419 | 1.29k | case rfbEncodingCoRRE: |
2420 | 1.54k | case rfbEncodingHextile: |
2421 | 1.80k | case rfbEncodingUltra: |
2422 | 1.80k | #ifdef LIBVNCSERVER_HAVE_LIBZ |
2423 | 2.03k | case rfbEncodingZlib: |
2424 | 2.48k | case rfbEncodingZRLE: |
2425 | 2.82k | case rfbEncodingZYWRLE: |
2426 | | #ifdef LIBVNCSERVER_HAVE_LIBJPEG |
2427 | | case rfbEncodingTight: |
2428 | | #endif |
2429 | 2.82k | #endif |
2430 | | #ifdef LIBVNCSERVER_HAVE_LIBPNG |
2431 | | case rfbEncodingTightPng: |
2432 | | #endif |
2433 | | /* The first supported encoding is the 'preferred' encoding */ |
2434 | 2.82k | if (cl->preferredEncoding == -1) |
2435 | 606 | cl->preferredEncoding = enc; |
2436 | | |
2437 | | |
2438 | 2.82k | break; |
2439 | 821 | case rfbEncodingXCursor: |
2440 | 821 | if(!cl->screen->dontConvertRichCursorToXCursor) { |
2441 | 821 | rfbLog("Enabling X-style cursor updates for client %s\n", |
2442 | 821 | cl->host); |
2443 | | /* if cursor was drawn, hide the cursor */ |
2444 | 821 | if(!cl->enableCursorShapeUpdates) |
2445 | 583 | rfbRedrawAfterHideCursor(cl,NULL); |
2446 | | |
2447 | 821 | cl->enableCursorShapeUpdates = TRUE; |
2448 | 821 | cl->cursorWasChanged = TRUE; |
2449 | 821 | } |
2450 | 821 | break; |
2451 | 2.07k | case rfbEncodingRichCursor: |
2452 | 2.07k | rfbLog("Enabling full-color cursor updates for client %s\n", |
2453 | 2.07k | cl->host); |
2454 | | /* if cursor was drawn, hide the cursor */ |
2455 | 2.07k | if(!cl->enableCursorShapeUpdates) |
2456 | 1.76k | rfbRedrawAfterHideCursor(cl,NULL); |
2457 | | |
2458 | 2.07k | cl->enableCursorShapeUpdates = TRUE; |
2459 | 2.07k | cl->useRichCursorEncoding = TRUE; |
2460 | 2.07k | cl->cursorWasChanged = TRUE; |
2461 | 2.07k | break; |
2462 | 646 | case rfbEncodingPointerPos: |
2463 | 646 | if (!cl->enableCursorPosUpdates) { |
2464 | 450 | rfbLog("Enabling cursor position updates for client %s\n", |
2465 | 450 | cl->host); |
2466 | 450 | cl->enableCursorPosUpdates = TRUE; |
2467 | 450 | cl->cursorWasMoved = TRUE; |
2468 | 450 | } |
2469 | 646 | break; |
2470 | 396 | case rfbEncodingLastRect: |
2471 | 396 | if (!cl->enableLastRectEncoding) { |
2472 | 202 | rfbLog("Enabling LastRect protocol extension for client " |
2473 | 202 | "%s\n", cl->host); |
2474 | 202 | cl->enableLastRectEncoding = TRUE; |
2475 | 202 | } |
2476 | 396 | break; |
2477 | 404 | case rfbEncodingNewFBSize: |
2478 | 404 | if (!cl->useNewFBSize) { |
2479 | 210 | rfbLog("Enabling NewFBSize protocol extension for client " |
2480 | 210 | "%s\n", cl->host); |
2481 | 210 | cl->useNewFBSize = TRUE; |
2482 | 210 | } |
2483 | 404 | break; |
2484 | 404 | case rfbEncodingExtDesktopSize: |
2485 | 404 | if (!cl->useExtDesktopSize) { |
2486 | 210 | rfbLog("Enabling ExtDesktopSize protocol extension for client " |
2487 | 210 | "%s\n", cl->host); |
2488 | 210 | cl->useExtDesktopSize = TRUE; |
2489 | 210 | cl->useNewFBSize = TRUE; |
2490 | 210 | } |
2491 | 404 | break; |
2492 | 425 | case rfbEncodingKeyboardLedState: |
2493 | 425 | if (!cl->enableKeyboardLedState) { |
2494 | 210 | rfbLog("Enabling KeyboardLedState protocol extension for client " |
2495 | 210 | "%s\n", cl->host); |
2496 | 210 | cl->enableKeyboardLedState = TRUE; |
2497 | 210 | } |
2498 | 425 | break; |
2499 | 396 | case rfbEncodingSupportedMessages: |
2500 | 396 | if (!cl->enableSupportedMessages) { |
2501 | 202 | rfbLog("Enabling SupportedMessages protocol extension for client " |
2502 | 202 | "%s\n", cl->host); |
2503 | 202 | cl->enableSupportedMessages = TRUE; |
2504 | 202 | } |
2505 | 396 | break; |
2506 | 1.00k | case rfbEncodingSupportedEncodings: |
2507 | 1.00k | if (!cl->enableSupportedEncodings) { |
2508 | 217 | rfbLog("Enabling SupportedEncodings protocol extension for client " |
2509 | 217 | "%s\n", cl->host); |
2510 | 217 | cl->enableSupportedEncodings = TRUE; |
2511 | 217 | } |
2512 | 1.00k | break; |
2513 | 402 | case rfbEncodingServerIdentity: |
2514 | 402 | if (!cl->enableServerIdentity) { |
2515 | 203 | rfbLog("Enabling ServerIdentity protocol extension for client " |
2516 | 203 | "%s\n", cl->host); |
2517 | 203 | cl->enableServerIdentity = TRUE; |
2518 | 203 | } |
2519 | 402 | break; |
2520 | 195 | case rfbEncodingXvp: |
2521 | 195 | if (cl->screen->xvpHook) { |
2522 | 0 | rfbLog("Enabling Xvp protocol extension for client " |
2523 | 0 | "%s\n", cl->host); |
2524 | 0 | if (!rfbSendXvp(cl, 1, rfbXvp_Init)) { |
2525 | 0 | rfbCloseClient(cl); |
2526 | 0 | return; |
2527 | 0 | } |
2528 | 0 | } |
2529 | 195 | break; |
2530 | 195 | #ifdef LIBVNCSERVER_HAVE_LIBZ |
2531 | 195 | case rfbEncodingExtendedClipboard: |
2532 | 194 | if (cl->screen->setXCutTextUTF8) { |
2533 | 0 | if (!cl->enableExtendedClipboard) { |
2534 | 0 | rfbLog("Enabling ExtendedClipboard extension for client " |
2535 | 0 | "%s\n", cl->host); |
2536 | 0 | cl->enableExtendedClipboard = TRUE; |
2537 | 0 | } |
2538 | | /* send the capabilities we support, currently only text */ |
2539 | 0 | if (!rfbSendExtendedClipboardCapability(cl)) { |
2540 | 0 | return; |
2541 | 0 | } |
2542 | 0 | } |
2543 | 194 | break; |
2544 | 194 | #endif |
2545 | 20.0k | default: |
2546 | 20.0k | #if defined(LIBVNCSERVER_HAVE_LIBZ) || defined(LIBVNCSERVER_HAVE_LIBPNG) |
2547 | 20.0k | if ( enc >= (uint32_t)rfbEncodingCompressLevel0 && |
2548 | 808 | enc <= (uint32_t)rfbEncodingCompressLevel9 ) { |
2549 | 204 | cl->zlibCompressLevel = enc & 0x0F; |
2550 | | #ifdef LIBVNCSERVER_HAVE_LIBJPEG |
2551 | | cl->tightCompressLevel = enc & 0x0F; |
2552 | | rfbLog("Using compression level %d for client %s\n", |
2553 | | cl->tightCompressLevel, cl->host); |
2554 | | #endif |
2555 | 19.8k | } else if ( enc >= (uint32_t)rfbEncodingQualityLevel0 && |
2556 | 563 | enc <= (uint32_t)rfbEncodingQualityLevel9 ) { |
2557 | 201 | cl->tightQualityLevel = enc & 0x0F; |
2558 | 201 | rfbLog("Using image quality level %d for client %s\n", |
2559 | 201 | cl->tightQualityLevel, cl->host); |
2560 | | #ifdef LIBVNCSERVER_HAVE_LIBJPEG |
2561 | | cl->turboQualityLevel = tight2turbo_qual[enc & 0x0F]; |
2562 | | cl->turboSubsampLevel = tight2turbo_subsamp[enc & 0x0F]; |
2563 | | rfbLog("Using JPEG subsampling %d, Q%d for client %s\n", |
2564 | | cl->turboSubsampLevel, cl->turboQualityLevel, cl->host); |
2565 | | } else if ( enc >= (uint32_t)rfbEncodingFineQualityLevel0 + 1 && |
2566 | | enc <= (uint32_t)rfbEncodingFineQualityLevel100 ) { |
2567 | | cl->turboQualityLevel = enc & 0xFF; |
2568 | | rfbLog("Using fine quality level %d for client %s\n", |
2569 | | cl->turboQualityLevel, cl->host); |
2570 | | } else if ( enc >= (uint32_t)rfbEncodingSubsamp1X && |
2571 | | enc <= (uint32_t)rfbEncodingSubsampGray ) { |
2572 | | cl->turboSubsampLevel = enc & 0xFF; |
2573 | | rfbLog("Using subsampling level %d for client %s\n", |
2574 | | cl->turboSubsampLevel, cl->host); |
2575 | | #endif |
2576 | 201 | } else |
2577 | 19.6k | #endif |
2578 | 19.6k | { |
2579 | 19.6k | rfbExtensionData* e; |
2580 | 19.6k | for(e = cl->extensions; e;) { |
2581 | 0 | rfbExtensionData* next = e->next; |
2582 | 0 | if(e->extension->enablePseudoEncoding && |
2583 | 0 | e->extension->enablePseudoEncoding(cl, |
2584 | 0 | &e->data, (int)enc)) |
2585 | | /* ext handles this encoding */ |
2586 | 0 | break; |
2587 | 0 | e = next; |
2588 | 0 | } |
2589 | 19.6k | if(e == NULL) { |
2590 | 19.6k | rfbBool handled = FALSE; |
2591 | | /* if the pseudo encoding is not handled by the |
2592 | | enabled extensions, search through all |
2593 | | extensions. */ |
2594 | 19.6k | rfbProtocolExtension* e; |
2595 | | |
2596 | 19.6k | for(e = rfbGetExtensionIterator(); e;) { |
2597 | 0 | int* encs = e->pseudoEncodings; |
2598 | 0 | while(encs && *encs!=0) { |
2599 | 0 | if(*encs==(int)enc) { |
2600 | 0 | void* data = NULL; |
2601 | 0 | if(!e->enablePseudoEncoding(cl, &data, (int)enc)) { |
2602 | 0 | rfbLog("Installed extension pretends to handle pseudo encoding 0x%x, but does not!\n",(int)enc); |
2603 | 0 | } else { |
2604 | 0 | rfbEnableExtension(cl, e, data); |
2605 | 0 | handled = TRUE; |
2606 | 0 | e = NULL; |
2607 | 0 | break; |
2608 | 0 | } |
2609 | 0 | } |
2610 | 0 | encs++; |
2611 | 0 | } |
2612 | |
|
2613 | 0 | if(e) |
2614 | 0 | e = e->next; |
2615 | 0 | } |
2616 | 19.6k | rfbReleaseExtensionIterator(); |
2617 | | |
2618 | 19.6k | if(!handled) |
2619 | 19.6k | rfbLog("rfbProcessClientNormalMessage: " |
2620 | 19.6k | "ignoring unsupported encoding type %s\n", |
2621 | 19.6k | encodingName(enc,encBuf,sizeof(encBuf))); |
2622 | 19.6k | } |
2623 | 19.6k | } |
2624 | 30.4k | } |
2625 | 30.4k | } |
2626 | | |
2627 | | |
2628 | | |
2629 | 6.24k | if (cl->preferredEncoding == -1) { |
2630 | 5.71k | if (lastPreferredEncoding==-1) { |
2631 | 273 | cl->preferredEncoding = rfbEncodingRaw; |
2632 | 273 | rfbLog("Defaulting to %s encoding for client %s\n", encodingName(cl->preferredEncoding,encBuf,sizeof(encBuf)),cl->host); |
2633 | 273 | } |
2634 | 5.44k | else { |
2635 | 5.44k | cl->preferredEncoding = lastPreferredEncoding; |
2636 | 5.44k | rfbLog("Sticking with %s encoding for client %s\n", encodingName(cl->preferredEncoding,encBuf,sizeof(encBuf)),cl->host); |
2637 | 5.44k | } |
2638 | 5.71k | } |
2639 | 533 | else |
2640 | 533 | { |
2641 | 533 | if (lastPreferredEncoding==-1) { |
2642 | 72 | rfbLog("Using %s encoding for client %s\n", encodingName(cl->preferredEncoding,encBuf,sizeof(encBuf)),cl->host); |
2643 | 461 | } else { |
2644 | 461 | rfbLog("Switching from %s to %s Encoding for client %s\n", |
2645 | 461 | encodingName(lastPreferredEncoding,encBuf2,sizeof(encBuf2)), |
2646 | 461 | encodingName(cl->preferredEncoding,encBuf,sizeof(encBuf)), cl->host); |
2647 | 461 | } |
2648 | 533 | } |
2649 | | |
2650 | 6.24k | if (cl->enableCursorPosUpdates && !cl->enableCursorShapeUpdates) { |
2651 | 209 | rfbLog("Disabling cursor position updates for client %s\n", |
2652 | 209 | cl->host); |
2653 | 209 | cl->enableCursorPosUpdates = FALSE; |
2654 | 209 | } |
2655 | | |
2656 | 6.24k | return; |
2657 | 6.88k | } |
2658 | | |
2659 | | |
2660 | 4.51k | case rfbFramebufferUpdateRequest: |
2661 | 4.51k | { |
2662 | 4.51k | sraRegionPtr tmpRegion; |
2663 | | |
2664 | 4.51k | if ((n = rfbReadExact(cl, ((char *)&msg) + 1, |
2665 | 4.51k | sz_rfbFramebufferUpdateRequestMsg-1)) <= 0) { |
2666 | 4 | if (n != 0) |
2667 | 0 | rfbLogPerror("rfbProcessClientNormalMessage: read"); |
2668 | 4 | rfbCloseClient(cl); |
2669 | 4 | return; |
2670 | 4 | } |
2671 | | |
2672 | 4.50k | rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbFramebufferUpdateRequestMsg,sz_rfbFramebufferUpdateRequestMsg); |
2673 | | |
2674 | | /* The values come in based on the scaled screen, we need to convert them to |
2675 | | * values based on the main screen's coordinate system |
2676 | | */ |
2677 | 4.50k | if(!rectSwapIfLEAndClip(&msg.fur.x,&msg.fur.y,&msg.fur.w,&msg.fur.h,cl)) |
2678 | 1.59k | { |
2679 | 1.59k | rfbLog("Warning, ignoring rfbFramebufferUpdateRequest: %dXx%dY-%dWx%dH\n",msg.fur.x, msg.fur.y, msg.fur.w, msg.fur.h); |
2680 | 1.59k | return; |
2681 | 1.59k | } |
2682 | | |
2683 | 2.91k | if (cl->clientFramebufferUpdateRequestHook) |
2684 | 0 | cl->clientFramebufferUpdateRequestHook(cl, &msg.fur); |
2685 | | |
2686 | 2.91k | tmpRegion = |
2687 | 2.91k | sraRgnCreateRect(msg.fur.x, |
2688 | 2.91k | msg.fur.y, |
2689 | 2.91k | msg.fur.x+msg.fur.w, |
2690 | 2.91k | msg.fur.y+msg.fur.h); |
2691 | | |
2692 | 2.91k | LOCK(cl->updateMutex); |
2693 | 2.91k | sraRgnOr(cl->requestedRegion,tmpRegion); |
2694 | | |
2695 | 2.91k | if (!cl->readyForSetColourMapEntries) { |
2696 | | /* client hasn't sent a SetPixelFormat so is using server's */ |
2697 | 333 | cl->readyForSetColourMapEntries = TRUE; |
2698 | 333 | if (!cl->format.trueColour) { |
2699 | 0 | if (!rfbSetClientColourMap(cl, 0, 0)) { |
2700 | 0 | sraRgnDestroy(tmpRegion); |
2701 | 0 | TSIGNAL(cl->updateCond); |
2702 | 0 | UNLOCK(cl->updateMutex); |
2703 | 0 | return; |
2704 | 0 | } |
2705 | 0 | } |
2706 | 333 | } |
2707 | | |
2708 | 2.91k | if (!msg.fur.incremental) { |
2709 | 2.05k | sraRgnOr(cl->modifiedRegion,tmpRegion); |
2710 | 2.05k | sraRgnSubtract(cl->copyRegion,tmpRegion); |
2711 | 2.05k | if (cl->useExtDesktopSize) |
2712 | 194 | cl->newFBSizePending = TRUE; |
2713 | 2.05k | } |
2714 | 2.91k | TSIGNAL(cl->updateCond); |
2715 | 2.91k | UNLOCK(cl->updateMutex); |
2716 | | |
2717 | 2.91k | sraRgnDestroy(tmpRegion); |
2718 | | |
2719 | 2.91k | return; |
2720 | 2.91k | } |
2721 | | |
2722 | 392 | case rfbKeyEvent: |
2723 | | |
2724 | 392 | if ((n = rfbReadExact(cl, ((char *)&msg) + 1, |
2725 | 392 | sz_rfbKeyEventMsg - 1)) <= 0) { |
2726 | 3 | if (n != 0) |
2727 | 0 | rfbLogPerror("rfbProcessClientNormalMessage: read"); |
2728 | 3 | rfbCloseClient(cl); |
2729 | 3 | return; |
2730 | 3 | } |
2731 | | |
2732 | 389 | rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbKeyEventMsg, sz_rfbKeyEventMsg); |
2733 | | |
2734 | 389 | if(!cl->viewOnly) { |
2735 | 389 | cl->screen->kbdAddEvent(msg.ke.down, (rfbKeySym)Swap32IfLE(msg.ke.key), cl); |
2736 | 389 | } |
2737 | | |
2738 | 389 | return; |
2739 | | |
2740 | | |
2741 | 9.11k | case rfbPointerEvent: |
2742 | | |
2743 | 9.11k | if ((n = rfbReadExact(cl, ((char *)&msg) + 1, |
2744 | 9.11k | sz_rfbPointerEventMsg - 1)) <= 0) { |
2745 | 9 | if (n != 0) |
2746 | 0 | rfbLogPerror("rfbProcessClientNormalMessage: read"); |
2747 | 9 | rfbCloseClient(cl); |
2748 | 9 | return; |
2749 | 9 | } |
2750 | | |
2751 | 9.10k | rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbPointerEventMsg, sz_rfbPointerEventMsg); |
2752 | | |
2753 | 9.10k | if (cl->screen->pointerClient && cl->screen->pointerClient != cl) |
2754 | 0 | return; |
2755 | | |
2756 | 9.10k | if (msg.pe.buttonMask == 0) |
2757 | 529 | cl->screen->pointerClient = NULL; |
2758 | 8.57k | else |
2759 | 8.57k | cl->screen->pointerClient = cl; |
2760 | | |
2761 | 9.10k | if(!cl->viewOnly) { |
2762 | 9.10k | if (msg.pe.buttonMask != cl->lastPtrButtons || |
2763 | 9.10k | cl->screen->deferPtrUpdateTime == 0) { |
2764 | 9.10k | cl->screen->ptrAddEvent(msg.pe.buttonMask, |
2765 | 9.10k | ScaleX(cl->scaledScreen, cl->screen, Swap16IfLE(msg.pe.x)), |
2766 | 9.10k | ScaleY(cl->scaledScreen, cl->screen, Swap16IfLE(msg.pe.y)), |
2767 | 9.10k | cl); |
2768 | 9.10k | cl->lastPtrButtons = msg.pe.buttonMask; |
2769 | 9.10k | } else { |
2770 | 0 | cl->lastPtrX = ScaleX(cl->scaledScreen, cl->screen, Swap16IfLE(msg.pe.x)); |
2771 | 0 | cl->lastPtrY = ScaleY(cl->scaledScreen, cl->screen, Swap16IfLE(msg.pe.y)); |
2772 | 0 | cl->lastPtrButtons = msg.pe.buttonMask; |
2773 | 0 | } |
2774 | 9.10k | } |
2775 | 9.10k | return; |
2776 | | |
2777 | | |
2778 | 3 | case rfbFileTransfer: |
2779 | 3 | if ((n = rfbReadExact(cl, ((char *)&msg) + 1, |
2780 | 3 | sz_rfbFileTransferMsg - 1)) <= 0) { |
2781 | 1 | if (n != 0) |
2782 | 0 | rfbLogPerror("rfbProcessClientNormalMessage: read"); |
2783 | 1 | rfbCloseClient(cl); |
2784 | 1 | return; |
2785 | 1 | } |
2786 | 2 | msg.ft.size = Swap32IfLE(msg.ft.size); |
2787 | 2 | msg.ft.length = Swap32IfLE(msg.ft.length); |
2788 | | /* record statistics in rfbProcessFileTransfer as length is filled with garbage when it is not valid */ |
2789 | 2 | rfbProcessFileTransfer(cl, msg.ft.contentType, msg.ft.contentParam, msg.ft.size, msg.ft.length); |
2790 | 2 | return; |
2791 | | |
2792 | 923 | case rfbSetSW: |
2793 | 923 | if ((n = rfbReadExact(cl, ((char *)&msg) + 1, |
2794 | 923 | sz_rfbSetSWMsg - 1)) <= 0) { |
2795 | 1 | if (n != 0) |
2796 | 0 | rfbLogPerror("rfbProcessClientNormalMessage: read"); |
2797 | 1 | rfbCloseClient(cl); |
2798 | 1 | return; |
2799 | 1 | } |
2800 | 922 | msg.sw.x = Swap16IfLE(msg.sw.x); |
2801 | 922 | msg.sw.y = Swap16IfLE(msg.sw.y); |
2802 | 922 | rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetSWMsg, sz_rfbSetSWMsg); |
2803 | | /* msg.sw.status is not initialized in the ultraVNC viewer and contains random numbers (why???) */ |
2804 | | |
2805 | 922 | rfbLog("Received a rfbSetSingleWindow(%d x, %d y)\n", msg.sw.x, msg.sw.y); |
2806 | 922 | if (cl->screen->setSingleWindow!=NULL) |
2807 | 0 | cl->screen->setSingleWindow(cl, msg.sw.x, msg.sw.y); |
2808 | 922 | return; |
2809 | | |
2810 | 351 | case rfbSetServerInput: |
2811 | 351 | if ((n = rfbReadExact(cl, ((char *)&msg) + 1, |
2812 | 351 | sz_rfbSetServerInputMsg - 1)) <= 0) { |
2813 | 1 | if (n != 0) |
2814 | 0 | rfbLogPerror("rfbProcessClientNormalMessage: read"); |
2815 | 1 | rfbCloseClient(cl); |
2816 | 1 | return; |
2817 | 1 | } |
2818 | 350 | rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetServerInputMsg, sz_rfbSetServerInputMsg); |
2819 | | |
2820 | | /* msg.sim.pad is not initialized in the ultraVNC viewer and contains random numbers (why???) */ |
2821 | | /* msg.sim.pad = Swap16IfLE(msg.sim.pad); */ |
2822 | | |
2823 | 350 | rfbLog("Received a rfbSetServerInput(%d status)\n", msg.sim.status); |
2824 | 350 | if (cl->screen->setServerInput!=NULL) |
2825 | 0 | cl->screen->setServerInput(cl, msg.sim.status); |
2826 | 350 | return; |
2827 | | |
2828 | 498 | case rfbTextChat: |
2829 | 498 | if ((n = rfbReadExact(cl, ((char *)&msg) + 1, |
2830 | 498 | sz_rfbTextChatMsg - 1)) <= 0) { |
2831 | 4 | if (n != 0) |
2832 | 0 | rfbLogPerror("rfbProcessClientNormalMessage: read"); |
2833 | 4 | rfbCloseClient(cl); |
2834 | 4 | return; |
2835 | 4 | } |
2836 | | |
2837 | 494 | msg.tc.pad2 = Swap16IfLE(msg.tc.pad2); |
2838 | 494 | msg.tc.length = Swap32IfLE(msg.tc.length); |
2839 | | |
2840 | 494 | switch (msg.tc.length) { |
2841 | 206 | case rfbTextChatOpen: |
2842 | 206 | case rfbTextChatClose: |
2843 | 225 | case rfbTextChatFinished: |
2844 | | /* commands do not have text following */ |
2845 | | /* Why couldn't they have used the pad byte??? */ |
2846 | 225 | str=NULL; |
2847 | 225 | rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbTextChatMsg, sz_rfbTextChatMsg); |
2848 | 225 | break; |
2849 | 269 | default: |
2850 | 269 | if ((msg.tc.length>0) && (msg.tc.length<rfbTextMaxSize)) |
2851 | 210 | { |
2852 | 210 | str = (char *)malloc(msg.tc.length); |
2853 | 210 | if (str==NULL) |
2854 | 0 | { |
2855 | 0 | rfbLog("Unable to malloc %d bytes for a TextChat Message\n", msg.tc.length); |
2856 | 0 | rfbCloseClient(cl); |
2857 | 0 | return; |
2858 | 0 | } |
2859 | 210 | if ((n = rfbReadExact(cl, str, msg.tc.length)) <= 0) { |
2860 | 16 | if (n != 0) |
2861 | 0 | rfbLogPerror("rfbProcessClientNormalMessage: read"); |
2862 | 16 | free(str); |
2863 | 16 | rfbCloseClient(cl); |
2864 | 16 | return; |
2865 | 16 | } |
2866 | 194 | rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbTextChatMsg+msg.tc.length, sz_rfbTextChatMsg+msg.tc.length); |
2867 | 194 | } |
2868 | 59 | else |
2869 | 59 | { |
2870 | | /* This should never happen */ |
2871 | 59 | rfbLog("client sent us a Text Message that is too big %d>%d\n", msg.tc.length, rfbTextMaxSize); |
2872 | 59 | rfbCloseClient(cl); |
2873 | 59 | return; |
2874 | 59 | } |
2875 | 494 | } |
2876 | | |
2877 | | /* Note: length can be commands: rfbTextChatOpen, rfbTextChatClose, and rfbTextChatFinished |
2878 | | * at which point, the str is NULL (as it is not sent) |
2879 | | */ |
2880 | 419 | if (cl->screen->setTextChat!=NULL) |
2881 | 0 | cl->screen->setTextChat(cl, msg.tc.length, str); |
2882 | | |
2883 | 419 | free(str); |
2884 | 419 | return; |
2885 | | |
2886 | | |
2887 | 361 | case rfbClientCutText: |
2888 | | |
2889 | 361 | if ((n = rfbReadExact(cl, ((char *)&msg) + 1, |
2890 | 361 | sz_rfbClientCutTextMsg - 1)) <= 0) { |
2891 | 2 | if (n != 0) |
2892 | 0 | rfbLogPerror("rfbProcessClientNormalMessage: read"); |
2893 | 2 | rfbCloseClient(cl); |
2894 | 2 | return; |
2895 | 2 | } |
2896 | | |
2897 | 359 | msg.cct.length = Swap32IfLE(msg.cct.length); |
2898 | | |
2899 | 359 | #ifdef LIBVNCSERVER_HAVE_LIBZ |
2900 | | /* when extended clipboard extention is enabled, a negative value of length |
2901 | | * indicates that the extended message format is used and abs(length) is the real length |
2902 | | */ |
2903 | 359 | if (cl->enableExtendedClipboard && (msg.cct.length & 0x80000000)) { |
2904 | 0 | msg.cct.length = -msg.cct.length; |
2905 | 0 | isExtendedCutText = TRUE; |
2906 | 0 | } |
2907 | 359 | #endif |
2908 | | |
2909 | | /* uint32_t input is passed to malloc()'s size_t argument, |
2910 | | * to rfbReadExact()'s int argument, to rfbStatRecordMessageRcvd()'s int |
2911 | | * argument increased of sz_rfbClientCutTextMsg, and to setXCutText()'s int |
2912 | | * argument. Here we impose a limit of 1 MB so that the value fits |
2913 | | * into all of the types to prevent from misinterpretation and thus |
2914 | | * from accessing uninitialized memory (CVE-2018-7225) and also to |
2915 | | * prevent from a denial-of-service by allocating too much memory in |
2916 | | * the server. */ |
2917 | 359 | if (msg.cct.length > 1<<20) { |
2918 | 20 | rfbLog("rfbClientCutText: too big cut text length requested: %u B > 1 MB\n", (unsigned int)msg.cct.length); |
2919 | 20 | rfbCloseClient(cl); |
2920 | 20 | return; |
2921 | 20 | } |
2922 | | |
2923 | | /* Allow zero-length client cut text. */ |
2924 | 339 | str = (char *)calloc(msg.cct.length ? msg.cct.length : 1, 1); |
2925 | 339 | if (str == NULL) { |
2926 | 0 | rfbLogPerror("rfbProcessClientNormalMessage: not enough memory"); |
2927 | 0 | rfbCloseClient(cl); |
2928 | 0 | return; |
2929 | 0 | } |
2930 | | |
2931 | 339 | if ((n = rfbReadExact(cl, str, msg.cct.length)) <= 0) { |
2932 | 48 | if (n != 0) |
2933 | 0 | rfbLogPerror("rfbProcessClientNormalMessage: read"); |
2934 | 48 | free(str); |
2935 | 48 | rfbCloseClient(cl); |
2936 | 48 | return; |
2937 | 48 | } |
2938 | 291 | rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbClientCutTextMsg+msg.cct.length, sz_rfbClientCutTextMsg+msg.cct.length); |
2939 | 291 | #ifdef LIBVNCSERVER_HAVE_LIBZ |
2940 | 291 | if (isExtendedCutText) { |
2941 | 0 | if (msg.cct.length < 4) { |
2942 | 0 | rfbLogPerror("rfbClientCutText: extended clipboard message is corrupted"); |
2943 | 0 | rfbCloseClient(cl); |
2944 | 0 | free(str); |
2945 | 0 | return; |
2946 | 0 | } |
2947 | 0 | memcpy(&extClipboardFlags, str, 4); |
2948 | 0 | extClipboardFlags = Swap32IfLE(extClipboardFlags); |
2949 | 0 | if (extClipboardFlags & rfbExtendedClipboard_Caps) { |
2950 | 0 | cl->extClipboardUserCap = extClipboardFlags; |
2951 | 0 | for (i = 0; i < 16; i++) { |
2952 | 0 | if (extClipboardFlags & (1 << i)) { |
2953 | 0 | extClipboardFormats++; |
2954 | 0 | } |
2955 | 0 | } |
2956 | 0 | if (extClipboardFormats == 0) { |
2957 | 0 | cl->enableExtendedClipboard = FALSE; |
2958 | 0 | } else if (msg.cct.length != 4 + extClipboardFormats * 4) { |
2959 | 0 | rfbLogPerror("rfbProcessClientNormalMessage: extended clipboard message is corrupted"); |
2960 | 0 | rfbCloseClient(cl); |
2961 | 0 | free(str); |
2962 | 0 | return; |
2963 | 0 | } |
2964 | 0 | if (extClipboardFlags & rfbExtendedClipboard_Text) { |
2965 | 0 | memcpy(&cl->extClipboardMaxUnsolicitedSize, str + 4, 4); |
2966 | 0 | cl->extClipboardMaxUnsolicitedSize = Swap32IfLE(cl->extClipboardMaxUnsolicitedSize); |
2967 | 0 | } else { |
2968 | 0 | cl->enableExtendedClipboard = FALSE; |
2969 | 0 | } |
2970 | 0 | free(str); |
2971 | 0 | return; |
2972 | 0 | } else if (extClipboardFlags & rfbExtendedClipboard_Request) { |
2973 | 0 | if ((cl->extClipboardUserCap & rfbExtendedClipboard_Provide) && |
2974 | 0 | cl->extClipboardData != NULL && cl->extClipboardDataSize > 0) { |
2975 | 0 | if (!rfbSendExtendedServerCutTextData(cl, cl->extClipboardData, cl->extClipboardDataSize)) { |
2976 | 0 | free(str); |
2977 | 0 | return; |
2978 | 0 | } |
2979 | 0 | } |
2980 | 0 | } else if (extClipboardFlags & rfbExtendedClipboard_Peek) { |
2981 | 0 | if ((cl->extClipboardUserCap & rfbExtendedClipboard_Notify) && |
2982 | 0 | cl->extClipboardData != NULL && cl->extClipboardDataSize > 0) { |
2983 | 0 | if (!rfbSendExtendedClipboardNotify(cl)) { |
2984 | 0 | free(str); |
2985 | 0 | return; |
2986 | 0 | } |
2987 | 0 | } |
2988 | 0 | } else if (extClipboardFlags & rfbExtendedClipboard_Provide) { |
2989 | 0 | if (!rfbProcessExtendedServerCutTextData(cl, extClipboardFlags, str + 4, msg.cct.length - 4)) { |
2990 | 0 | free(str); |
2991 | 0 | return; |
2992 | 0 | } |
2993 | 0 | } |
2994 | 0 | free(str); |
2995 | 291 | } else { |
2996 | 291 | if(!cl->viewOnly) { |
2997 | 291 | cl->screen->setXCutText(str, msg.cct.length, cl); |
2998 | 291 | } |
2999 | 291 | free(str); |
3000 | 291 | } |
3001 | | #else |
3002 | | if(!cl->viewOnly) { |
3003 | | cl->screen->setXCutText(str, msg.cct.length, cl); |
3004 | | } |
3005 | | free(str); |
3006 | | #endif |
3007 | | |
3008 | 291 | return; |
3009 | | |
3010 | 1.86k | case rfbPalmVNCSetScaleFactor: |
3011 | 1.86k | cl->PalmVNC = TRUE; |
3012 | 1.86k | if ((n = rfbReadExact(cl, ((char *)&msg) + 1, |
3013 | 1.86k | sz_rfbSetScaleMsg - 1)) <= 0) { |
3014 | 6 | if (n != 0) |
3015 | 0 | rfbLogPerror("rfbProcessClientNormalMessage: read"); |
3016 | 6 | rfbCloseClient(cl); |
3017 | 6 | return; |
3018 | 6 | } |
3019 | | |
3020 | 1.86k | if (msg.ssc.scale == 0) { |
3021 | 1 | rfbLogPerror("rfbProcessClientNormalMessage: will not accept a scale factor of zero"); |
3022 | 1 | rfbCloseClient(cl); |
3023 | 1 | return; |
3024 | 1 | } |
3025 | | |
3026 | 1.86k | rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetScaleMsg, sz_rfbSetScaleMsg); |
3027 | 1.86k | rfbLog("rfbSetScale(%d)\n", msg.ssc.scale); |
3028 | 1.86k | rfbScalingSetup(cl,cl->screen->width/msg.ssc.scale, cl->screen->height/msg.ssc.scale); |
3029 | | |
3030 | 1.86k | rfbSendNewScaleSize(cl); |
3031 | 1.86k | return; |
3032 | | |
3033 | 2.54k | case rfbSetScale: |
3034 | | |
3035 | 2.54k | if ((n = rfbReadExact(cl, ((char *)&msg) + 1, |
3036 | 2.54k | sz_rfbSetScaleMsg - 1)) <= 0) { |
3037 | 7 | if (n != 0) |
3038 | 0 | rfbLogPerror("rfbProcessClientNormalMessage: read"); |
3039 | 7 | rfbCloseClient(cl); |
3040 | 7 | return; |
3041 | 7 | } |
3042 | | |
3043 | 2.53k | if (msg.ssc.scale == 0) { |
3044 | 3 | rfbLogPerror("rfbProcessClientNormalMessage: will not accept a scale factor of zero"); |
3045 | 3 | rfbCloseClient(cl); |
3046 | 3 | return; |
3047 | 3 | } |
3048 | | |
3049 | 2.53k | rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetScaleMsg, sz_rfbSetScaleMsg); |
3050 | 2.53k | rfbLog("rfbSetScale(%d)\n", msg.ssc.scale); |
3051 | 2.53k | rfbScalingSetup(cl,cl->screen->width/msg.ssc.scale, cl->screen->height/msg.ssc.scale); |
3052 | | |
3053 | 2.53k | rfbSendNewScaleSize(cl); |
3054 | 2.53k | return; |
3055 | | |
3056 | 33.8k | case rfbXvp: |
3057 | | |
3058 | 33.8k | if ((n = rfbReadExact(cl, ((char *)&msg) + 1, |
3059 | 33.8k | sz_rfbXvpMsg - 1)) <= 0) { |
3060 | 2 | if (n != 0) |
3061 | 0 | rfbLogPerror("rfbProcessClientNormalMessage: read"); |
3062 | 2 | rfbCloseClient(cl); |
3063 | 2 | return; |
3064 | 2 | } |
3065 | 33.8k | rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbXvpMsg, sz_rfbXvpMsg); |
3066 | | |
3067 | | /* only version when is defined, so echo back a fail */ |
3068 | 33.8k | if(msg.xvp.version != 1) { |
3069 | 33.6k | rfbSendXvp(cl, msg.xvp.version, rfbXvp_Fail); |
3070 | 33.6k | } |
3071 | 205 | else { |
3072 | | /* if the hook exists and fails, send a fail msg */ |
3073 | 205 | if(cl->screen->xvpHook && !cl->screen->xvpHook(cl, msg.xvp.version, msg.xvp.code)) |
3074 | 0 | rfbSendXvp(cl, 1, rfbXvp_Fail); |
3075 | 205 | } |
3076 | 33.8k | return; |
3077 | | |
3078 | 553 | case rfbSetDesktopSize: |
3079 | | |
3080 | 553 | if ((n = rfbReadExact(cl, ((char *)&msg) + 1, |
3081 | 553 | sz_rfbSetDesktopSizeMsg - 1)) <= 0) { |
3082 | 2 | if (n != 0) |
3083 | 0 | rfbLogPerror("rfbProcessClientNormalMessage: read"); |
3084 | 2 | rfbCloseClient(cl); |
3085 | 2 | return; |
3086 | 2 | } |
3087 | | |
3088 | 551 | if (msg.sdm.numberOfScreens == 0) { |
3089 | 325 | rfbLog("Ignoring setDesktopSize message from client that defines zero screens\n"); |
3090 | 325 | return; |
3091 | 325 | } |
3092 | | |
3093 | 226 | extDesktopScreens = (rfbExtDesktopScreen *) malloc(msg.sdm.numberOfScreens * sz_rfbExtDesktopScreen); |
3094 | 226 | if (extDesktopScreens == NULL) { |
3095 | 0 | rfbLogPerror("rfbProcessClientNormalMessage: not enough memory"); |
3096 | 0 | rfbCloseClient(cl); |
3097 | 0 | return; |
3098 | 0 | } |
3099 | | |
3100 | 226 | if ((n = rfbReadExact(cl, ((char *)extDesktopScreens), msg.sdm.numberOfScreens * sz_rfbExtDesktopScreen)) <= 0) { |
3101 | 9 | if (n != 0) |
3102 | 0 | rfbLogPerror("rfbProcessClientNormalMessage: read"); |
3103 | 9 | free(extDesktopScreens); |
3104 | 9 | rfbCloseClient(cl); |
3105 | 9 | return; |
3106 | 9 | } |
3107 | 217 | rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetDesktopSizeMsg + msg.sdm.numberOfScreens * sz_rfbExtDesktopScreen, |
3108 | 217 | sz_rfbSetDesktopSizeMsg + msg.sdm.numberOfScreens * sz_rfbExtDesktopScreen); |
3109 | | |
3110 | 1.56k | for (i=0; i < msg.sdm.numberOfScreens; i++) { |
3111 | 1.34k | extDesktopScreens[i].id = Swap32IfLE(extDesktopScreens[i].id); |
3112 | 1.34k | extDesktopScreens[i].x = Swap16IfLE(extDesktopScreens[i].x); |
3113 | 1.34k | extDesktopScreens[i].y = Swap16IfLE(extDesktopScreens[i].y); |
3114 | 1.34k | extDesktopScreens[i].width = Swap16IfLE(extDesktopScreens[i].width); |
3115 | 1.34k | extDesktopScreens[i].height = Swap16IfLE(extDesktopScreens[i].height); |
3116 | 1.34k | extDesktopScreens[i].flags = Swap32IfLE(extDesktopScreens[i].flags); |
3117 | 1.34k | } |
3118 | 217 | msg.sdm.width = Swap16IfLE(msg.sdm.width); |
3119 | 217 | msg.sdm.height = Swap16IfLE(msg.sdm.height); |
3120 | | |
3121 | 217 | rfbLog("Client requested resolution change to (%dx%d)\n", msg.sdm.width, msg.sdm.height); |
3122 | 217 | cl->requestedDesktopSizeChange = rfbExtDesktopSize_ClientRequestedChange; |
3123 | 217 | cl->lastDesktopSizeChangeError = cl->screen->setDesktopSizeHook(msg.sdm.width, msg.sdm.height, msg.sdm.numberOfScreens, |
3124 | 217 | extDesktopScreens, cl); |
3125 | | |
3126 | 217 | if (cl->lastDesktopSizeChangeError == 0) { |
3127 | | /* Let other clients know it was this client that requested the change */ |
3128 | 0 | iterator = rfbGetClientIterator(cl->screen); |
3129 | 0 | while ((clp = rfbClientIteratorNext(iterator)) != NULL) { |
3130 | 0 | LOCK(clp->updateMutex); |
3131 | 0 | if (clp != cl) |
3132 | 0 | clp->requestedDesktopSizeChange = rfbExtDesktopSize_OtherClientRequestedChange; |
3133 | 0 | UNLOCK(clp->updateMutex); |
3134 | 0 | } |
3135 | 0 | } |
3136 | 217 | else |
3137 | 217 | { |
3138 | | /* Force ExtendedDesktopSize message to be sent with result code in case of error. |
3139 | | (In case of success, it is delayed until the new framebuffer is created) */ |
3140 | 217 | cl->newFBSizePending = TRUE; |
3141 | 217 | } |
3142 | | |
3143 | 217 | free(extDesktopScreens); |
3144 | 217 | return; |
3145 | | |
3146 | 70 | default: |
3147 | 70 | { |
3148 | 70 | rfbExtensionData *e,*next; |
3149 | | |
3150 | 70 | for(e=cl->extensions; e;) { |
3151 | 0 | next = e->next; |
3152 | 0 | if(e->extension->handleMessage && |
3153 | 0 | e->extension->handleMessage(cl, e->data, &msg)) |
3154 | 0 | { |
3155 | 0 | rfbStatRecordMessageRcvd(cl, msg.type, 0, 0); /* Extension should handle this */ |
3156 | 0 | return; |
3157 | 0 | } |
3158 | 0 | e = next; |
3159 | 0 | } |
3160 | | |
3161 | 70 | rfbLog("rfbProcessClientNormalMessage: unknown message type %d\n", |
3162 | 70 | msg.type); |
3163 | 70 | rfbLog(" ... closing connection\n"); |
3164 | 70 | rfbCloseClient(cl); |
3165 | 70 | return; |
3166 | 70 | } |
3167 | 72.4k | } |
3168 | 72.4k | } |
3169 | | |
3170 | | |
3171 | | |
3172 | | /* |
3173 | | * rfbSendFramebufferUpdate - send the currently pending framebuffer update to |
3174 | | * the RFB client. |
3175 | | * givenUpdateRegion is not changed. |
3176 | | */ |
3177 | | |
3178 | | rfbBool |
3179 | | rfbSendFramebufferUpdate(rfbClientPtr cl, |
3180 | | sraRegionPtr givenUpdateRegion) |
3181 | 0 | { |
3182 | 0 | sraRectangleIterator* i=NULL; |
3183 | 0 | sraRect rect; |
3184 | 0 | int nUpdateRegionRects; |
3185 | 0 | rfbFramebufferUpdateMsg *fu = (rfbFramebufferUpdateMsg *)cl->updateBuf; |
3186 | 0 | sraRegionPtr updateRegion,updateCopyRegion,tmpRegion; |
3187 | 0 | int dx, dy; |
3188 | 0 | rfbBool sendCursorShape = FALSE; |
3189 | 0 | rfbBool sendCursorPos = FALSE; |
3190 | 0 | rfbBool sendKeyboardLedState = FALSE; |
3191 | 0 | rfbBool sendSupportedMessages = FALSE; |
3192 | 0 | rfbBool sendSupportedEncodings = FALSE; |
3193 | 0 | rfbBool sendServerIdentity = FALSE; |
3194 | 0 | rfbBool result = TRUE; |
3195 | | |
3196 | |
|
3197 | 0 | if(cl->screen->displayHook) |
3198 | 0 | cl->screen->displayHook(cl); |
3199 | | |
3200 | | /* |
3201 | | * If framebuffer size was changed and the client supports NewFBSize |
3202 | | * encoding, just send NewFBSize marker and return. |
3203 | | */ |
3204 | |
|
3205 | 0 | if (cl->useNewFBSize && cl->newFBSizePending) { |
3206 | 0 | LOCK(cl->updateMutex); |
3207 | 0 | cl->newFBSizePending = FALSE; |
3208 | 0 | UNLOCK(cl->updateMutex); |
3209 | 0 | fu->type = rfbFramebufferUpdate; |
3210 | 0 | fu->nRects = Swap16IfLE(1); |
3211 | 0 | cl->ublen = sz_rfbFramebufferUpdateMsg; |
3212 | |
|
3213 | 0 | if (cl->useExtDesktopSize) { |
3214 | 0 | if (!rfbSendExtDesktopSize(cl, cl->scaledScreen->width, cl->scaledScreen->height)) { |
3215 | 0 | if(cl->screen->displayFinishedHook) |
3216 | 0 | cl->screen->displayFinishedHook(cl, FALSE); |
3217 | 0 | return FALSE; |
3218 | 0 | } |
3219 | 0 | } |
3220 | 0 | else if (!rfbSendNewFBSize(cl, cl->scaledScreen->width, cl->scaledScreen->height)) { |
3221 | 0 | if(cl->screen->displayFinishedHook) |
3222 | 0 | cl->screen->displayFinishedHook(cl, FALSE); |
3223 | 0 | return FALSE; |
3224 | 0 | } |
3225 | 0 | result = rfbSendUpdateBuf(cl); |
3226 | 0 | if(cl->screen->displayFinishedHook) |
3227 | 0 | cl->screen->displayFinishedHook(cl, result); |
3228 | 0 | return result; |
3229 | 0 | } |
3230 | | |
3231 | | /* |
3232 | | * If this client understands cursor shape updates, cursor should be |
3233 | | * removed from the framebuffer. Otherwise, make sure it's put up. |
3234 | | */ |
3235 | | |
3236 | 0 | if (cl->enableCursorShapeUpdates) { |
3237 | 0 | if (cl->cursorWasChanged && cl->readyForSetColourMapEntries) |
3238 | 0 | sendCursorShape = TRUE; |
3239 | 0 | } |
3240 | | |
3241 | | /* |
3242 | | * Do we plan to send cursor position update? |
3243 | | */ |
3244 | |
|
3245 | 0 | if (cl->enableCursorPosUpdates && cl->cursorWasMoved) |
3246 | 0 | sendCursorPos = TRUE; |
3247 | | |
3248 | | /* |
3249 | | * Do we plan to send a keyboard state update? |
3250 | | */ |
3251 | 0 | if ((cl->enableKeyboardLedState) && |
3252 | 0 | (cl->screen->getKeyboardLedStateHook!=NULL)) |
3253 | 0 | { |
3254 | 0 | int x; |
3255 | 0 | x=cl->screen->getKeyboardLedStateHook(cl->screen); |
3256 | 0 | if (x!=cl->lastKeyboardLedState) |
3257 | 0 | { |
3258 | 0 | sendKeyboardLedState = TRUE; |
3259 | 0 | cl->lastKeyboardLedState=x; |
3260 | 0 | } |
3261 | 0 | } |
3262 | | |
3263 | | /* |
3264 | | * Do we plan to send a rfbEncodingSupportedMessages? |
3265 | | */ |
3266 | 0 | if (cl->enableSupportedMessages) |
3267 | 0 | { |
3268 | 0 | sendSupportedMessages = TRUE; |
3269 | | /* We only send this message ONCE <per setEncodings message received> |
3270 | | * (We disable it here) |
3271 | | */ |
3272 | 0 | cl->enableSupportedMessages = FALSE; |
3273 | 0 | } |
3274 | | /* |
3275 | | * Do we plan to send a rfbEncodingSupportedEncodings? |
3276 | | */ |
3277 | 0 | if (cl->enableSupportedEncodings) |
3278 | 0 | { |
3279 | 0 | sendSupportedEncodings = TRUE; |
3280 | | /* We only send this message ONCE <per setEncodings message received> |
3281 | | * (We disable it here) |
3282 | | */ |
3283 | 0 | cl->enableSupportedEncodings = FALSE; |
3284 | 0 | } |
3285 | | /* |
3286 | | * Do we plan to send a rfbEncodingServerIdentity? |
3287 | | */ |
3288 | 0 | if (cl->enableServerIdentity) |
3289 | 0 | { |
3290 | 0 | sendServerIdentity = TRUE; |
3291 | | /* We only send this message ONCE <per setEncodings message received> |
3292 | | * (We disable it here) |
3293 | | */ |
3294 | 0 | cl->enableServerIdentity = FALSE; |
3295 | 0 | } |
3296 | |
|
3297 | 0 | LOCK(cl->updateMutex); |
3298 | | |
3299 | | /* |
3300 | | * The modifiedRegion may overlap the destination copyRegion. We remove |
3301 | | * any overlapping bits from the copyRegion (since they'd only be |
3302 | | * overwritten anyway). |
3303 | | */ |
3304 | | |
3305 | 0 | sraRgnSubtract(cl->copyRegion,cl->modifiedRegion); |
3306 | | |
3307 | | /* |
3308 | | * The client is interested in the region requestedRegion. The region |
3309 | | * which should be updated now is the intersection of requestedRegion |
3310 | | * and the union of modifiedRegion and copyRegion. If it's empty then |
3311 | | * no update is needed. |
3312 | | */ |
3313 | |
|
3314 | 0 | updateRegion = sraRgnCreateRgn(givenUpdateRegion); |
3315 | 0 | if(cl->screen->progressiveSliceHeight>0) { |
3316 | 0 | int height=cl->screen->progressiveSliceHeight, |
3317 | 0 | y=cl->progressiveSliceY; |
3318 | 0 | sraRegionPtr bbox=sraRgnBBox(updateRegion); |
3319 | 0 | sraRect rect; |
3320 | 0 | if(sraRgnPopRect(bbox,&rect,0)) { |
3321 | 0 | sraRegionPtr slice; |
3322 | 0 | if(y<rect.y1 || y>=rect.y2) |
3323 | 0 | y=rect.y1; |
3324 | 0 | slice=sraRgnCreateRect(0,y,cl->screen->width,y+height); |
3325 | 0 | sraRgnAnd(updateRegion,slice); |
3326 | 0 | sraRgnDestroy(slice); |
3327 | 0 | } |
3328 | 0 | sraRgnDestroy(bbox); |
3329 | 0 | y+=height; |
3330 | 0 | if(y>=cl->screen->height) |
3331 | 0 | y=0; |
3332 | 0 | cl->progressiveSliceY=y; |
3333 | 0 | } |
3334 | |
|
3335 | 0 | sraRgnOr(updateRegion,cl->copyRegion); |
3336 | 0 | if(!sraRgnAnd(updateRegion,cl->requestedRegion) && |
3337 | 0 | sraRgnEmpty(updateRegion) && |
3338 | 0 | (cl->enableCursorShapeUpdates || |
3339 | 0 | (cl->cursorX == cl->screen->cursorX && cl->cursorY == cl->screen->cursorY)) && |
3340 | 0 | !sendCursorShape && !sendCursorPos && !sendKeyboardLedState && |
3341 | 0 | !sendSupportedMessages && !sendSupportedEncodings && !sendServerIdentity) { |
3342 | 0 | sraRgnDestroy(updateRegion); |
3343 | 0 | UNLOCK(cl->updateMutex); |
3344 | 0 | if(cl->screen->displayFinishedHook) |
3345 | 0 | cl->screen->displayFinishedHook(cl, TRUE); |
3346 | 0 | return TRUE; |
3347 | 0 | } |
3348 | | |
3349 | | /* |
3350 | | * We assume that the client doesn't have any pixel data outside the |
3351 | | * requestedRegion. In other words, both the source and destination of a |
3352 | | * copy must lie within requestedRegion. So the region we can send as a |
3353 | | * copy is the intersection of the copyRegion with both the requestedRegion |
3354 | | * and the requestedRegion translated by the amount of the copy. We set |
3355 | | * updateCopyRegion to this. |
3356 | | */ |
3357 | | |
3358 | 0 | updateCopyRegion = sraRgnCreateRgn(cl->copyRegion); |
3359 | 0 | sraRgnAnd(updateCopyRegion,cl->requestedRegion); |
3360 | 0 | tmpRegion = sraRgnCreateRgn(cl->requestedRegion); |
3361 | 0 | sraRgnOffset(tmpRegion,cl->copyDX,cl->copyDY); |
3362 | 0 | sraRgnAnd(updateCopyRegion,tmpRegion); |
3363 | 0 | sraRgnDestroy(tmpRegion); |
3364 | 0 | dx = cl->copyDX; |
3365 | 0 | dy = cl->copyDY; |
3366 | | |
3367 | | /* |
3368 | | * Next we remove updateCopyRegion from updateRegion so that updateRegion |
3369 | | * is the part of this update which is sent as ordinary pixel data (i.e not |
3370 | | * a copy). |
3371 | | */ |
3372 | |
|
3373 | 0 | sraRgnSubtract(updateRegion,updateCopyRegion); |
3374 | | |
3375 | | /* |
3376 | | * Finally we leave modifiedRegion to be the remainder (if any) of parts of |
3377 | | * the screen which are modified but outside the requestedRegion. We also |
3378 | | * empty both the requestedRegion and the copyRegion - note that we never |
3379 | | * carry over a copyRegion for a future update. |
3380 | | */ |
3381 | |
|
3382 | 0 | sraRgnOr(cl->modifiedRegion,cl->copyRegion); |
3383 | 0 | sraRgnSubtract(cl->modifiedRegion,updateRegion); |
3384 | 0 | sraRgnSubtract(cl->modifiedRegion,updateCopyRegion); |
3385 | |
|
3386 | 0 | sraRgnMakeEmpty(cl->requestedRegion); |
3387 | 0 | sraRgnMakeEmpty(cl->copyRegion); |
3388 | 0 | cl->copyDX = 0; |
3389 | 0 | cl->copyDY = 0; |
3390 | | |
3391 | 0 | UNLOCK(cl->updateMutex); |
3392 | | |
3393 | 0 | if (!cl->enableCursorShapeUpdates) { |
3394 | 0 | if(cl->cursorX != cl->screen->cursorX || cl->cursorY != cl->screen->cursorY) { |
3395 | 0 | rfbRedrawAfterHideCursor(cl,updateRegion); |
3396 | 0 | LOCK(cl->screen->cursorMutex); |
3397 | 0 | cl->cursorX = cl->screen->cursorX; |
3398 | 0 | cl->cursorY = cl->screen->cursorY; |
3399 | 0 | UNLOCK(cl->screen->cursorMutex); |
3400 | 0 | rfbRedrawAfterHideCursor(cl,updateRegion); |
3401 | 0 | } |
3402 | 0 | rfbShowCursor(cl); |
3403 | 0 | } |
3404 | | |
3405 | | /* |
3406 | | * Now send the update. |
3407 | | */ |
3408 | | |
3409 | 0 | rfbStatRecordMessageSent(cl, rfbFramebufferUpdate, 0, 0); |
3410 | 0 | if (cl->preferredEncoding == rfbEncodingCoRRE) { |
3411 | 0 | nUpdateRegionRects = 0; |
3412 | |
|
3413 | 0 | for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){ |
3414 | 0 | int x = rect.x1; |
3415 | 0 | int y = rect.y1; |
3416 | 0 | int w = rect.x2 - x; |
3417 | 0 | int h = rect.y2 - y; |
3418 | 0 | int rectsPerRow, rows; |
3419 | | /* We need to count the number of rects in the scaled screen */ |
3420 | 0 | if (cl->screen!=cl->scaledScreen) |
3421 | 0 | rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate"); |
3422 | 0 | rectsPerRow = (w-1)/cl->correMaxWidth+1; |
3423 | 0 | rows = (h-1)/cl->correMaxHeight+1; |
3424 | 0 | nUpdateRegionRects += rectsPerRow*rows; |
3425 | 0 | } |
3426 | 0 | sraRgnReleaseIterator(i); i=NULL; |
3427 | 0 | } else if (cl->preferredEncoding == rfbEncodingUltra) { |
3428 | 0 | nUpdateRegionRects = 0; |
3429 | | |
3430 | 0 | for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){ |
3431 | 0 | int x = rect.x1; |
3432 | 0 | int y = rect.y1; |
3433 | 0 | int w = rect.x2 - x; |
3434 | 0 | int h = rect.y2 - y; |
3435 | | /* We need to count the number of rects in the scaled screen */ |
3436 | 0 | if (cl->screen!=cl->scaledScreen) |
3437 | 0 | rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate"); |
3438 | 0 | nUpdateRegionRects += (((h-1) / (ULTRA_MAX_SIZE( w ) / w)) + 1); |
3439 | 0 | } |
3440 | 0 | sraRgnReleaseIterator(i); i=NULL; |
3441 | 0 | #ifdef LIBVNCSERVER_HAVE_LIBZ |
3442 | 0 | } else if (cl->preferredEncoding == rfbEncodingZlib) { |
3443 | 0 | nUpdateRegionRects = 0; |
3444 | |
|
3445 | 0 | for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){ |
3446 | 0 | int x = rect.x1; |
3447 | 0 | int y = rect.y1; |
3448 | 0 | int w = rect.x2 - x; |
3449 | 0 | int h = rect.y2 - y; |
3450 | | /* We need to count the number of rects in the scaled screen */ |
3451 | 0 | if (cl->screen!=cl->scaledScreen) |
3452 | 0 | rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate"); |
3453 | 0 | nUpdateRegionRects += (((h-1) / (ZLIB_MAX_SIZE( w ) / w)) + 1); |
3454 | 0 | } |
3455 | 0 | sraRgnReleaseIterator(i); i=NULL; |
3456 | | #ifdef LIBVNCSERVER_HAVE_LIBJPEG |
3457 | | } else if (cl->preferredEncoding == rfbEncodingTight) { |
3458 | | nUpdateRegionRects = 0; |
3459 | | |
3460 | | for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){ |
3461 | | int x = rect.x1; |
3462 | | int y = rect.y1; |
3463 | | int w = rect.x2 - x; |
3464 | | int h = rect.y2 - y; |
3465 | | int n; |
3466 | | /* We need to count the number of rects in the scaled screen */ |
3467 | | if (cl->screen!=cl->scaledScreen) |
3468 | | rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate"); |
3469 | | n = rfbNumCodedRectsTight(cl, x, y, w, h); |
3470 | | if (n == 0) { |
3471 | | nUpdateRegionRects = 0xFFFF; |
3472 | | break; |
3473 | | } |
3474 | | nUpdateRegionRects += n; |
3475 | | } |
3476 | | sraRgnReleaseIterator(i); i=NULL; |
3477 | | #endif |
3478 | 0 | #endif |
3479 | | #if defined(LIBVNCSERVER_HAVE_LIBJPEG) && defined(LIBVNCSERVER_HAVE_LIBPNG) |
3480 | | } else if (cl->preferredEncoding == rfbEncodingTightPng) { |
3481 | | nUpdateRegionRects = 0; |
3482 | | |
3483 | | for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){ |
3484 | | int x = rect.x1; |
3485 | | int y = rect.y1; |
3486 | | int w = rect.x2 - x; |
3487 | | int h = rect.y2 - y; |
3488 | | int n; |
3489 | | /* We need to count the number of rects in the scaled screen */ |
3490 | | if (cl->screen!=cl->scaledScreen) |
3491 | | rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate"); |
3492 | | n = rfbNumCodedRectsTight(cl, x, y, w, h); |
3493 | | if (n == 0) { |
3494 | | nUpdateRegionRects = 0xFFFF; |
3495 | | break; |
3496 | | } |
3497 | | nUpdateRegionRects += n; |
3498 | | } |
3499 | | sraRgnReleaseIterator(i); i=NULL; |
3500 | | #endif |
3501 | 0 | } else { |
3502 | 0 | nUpdateRegionRects = sraRgnCountRects(updateRegion); |
3503 | 0 | } |
3504 | |
|
3505 | 0 | fu->type = rfbFramebufferUpdate; |
3506 | 0 | if (nUpdateRegionRects != 0xFFFF) { |
3507 | 0 | if(cl->screen->maxRectsPerUpdate>0 |
3508 | | /* CoRRE splits the screen into smaller squares */ |
3509 | 0 | && cl->preferredEncoding != rfbEncodingCoRRE |
3510 | | /* Ultra encoding splits rectangles up into smaller chunks */ |
3511 | 0 | && cl->preferredEncoding != rfbEncodingUltra |
3512 | 0 | #ifdef LIBVNCSERVER_HAVE_LIBZ |
3513 | | /* Zlib encoding splits rectangles up into smaller chunks */ |
3514 | 0 | && cl->preferredEncoding != rfbEncodingZlib |
3515 | | #ifdef LIBVNCSERVER_HAVE_LIBJPEG |
3516 | | /* Tight encoding counts the rectangles differently */ |
3517 | | && cl->preferredEncoding != rfbEncodingTight |
3518 | | #endif |
3519 | 0 | #endif |
3520 | | #ifdef LIBVNCSERVER_HAVE_LIBPNG |
3521 | | /* Tight encoding counts the rectangles differently */ |
3522 | | && cl->preferredEncoding != rfbEncodingTightPng |
3523 | | #endif |
3524 | 0 | && nUpdateRegionRects>cl->screen->maxRectsPerUpdate) { |
3525 | 0 | sraRegion* newUpdateRegion = sraRgnBBox(updateRegion); |
3526 | 0 | sraRgnDestroy(updateRegion); |
3527 | 0 | updateRegion = newUpdateRegion; |
3528 | 0 | nUpdateRegionRects = sraRgnCountRects(updateRegion); |
3529 | 0 | } |
3530 | 0 | fu->nRects = Swap16IfLE((uint16_t)(sraRgnCountRects(updateCopyRegion) + |
3531 | 0 | nUpdateRegionRects + |
3532 | 0 | !!sendCursorShape + !!sendCursorPos + !!sendKeyboardLedState + |
3533 | 0 | !!sendSupportedMessages + !!sendSupportedEncodings + !!sendServerIdentity)); |
3534 | 0 | } else { |
3535 | 0 | fu->nRects = 0xFFFF; |
3536 | 0 | } |
3537 | 0 | cl->ublen = sz_rfbFramebufferUpdateMsg; |
3538 | |
|
3539 | 0 | if (sendCursorShape) { |
3540 | 0 | cl->cursorWasChanged = FALSE; |
3541 | 0 | if (!rfbSendCursorShape(cl)) |
3542 | 0 | goto updateFailed; |
3543 | 0 | } |
3544 | | |
3545 | 0 | if (sendCursorPos) { |
3546 | 0 | cl->cursorWasMoved = FALSE; |
3547 | 0 | if (!rfbSendCursorPos(cl)) |
3548 | 0 | goto updateFailed; |
3549 | 0 | } |
3550 | | |
3551 | 0 | if (sendKeyboardLedState) { |
3552 | 0 | if (!rfbSendKeyboardLedState(cl)) |
3553 | 0 | goto updateFailed; |
3554 | 0 | } |
3555 | | |
3556 | 0 | if (sendSupportedMessages) { |
3557 | 0 | if (!rfbSendSupportedMessages(cl)) |
3558 | 0 | goto updateFailed; |
3559 | 0 | } |
3560 | 0 | if (sendSupportedEncodings) { |
3561 | 0 | if (!rfbSendSupportedEncodings(cl)) |
3562 | 0 | goto updateFailed; |
3563 | 0 | } |
3564 | 0 | if (sendServerIdentity) { |
3565 | 0 | if (!rfbSendServerIdentity(cl)) |
3566 | 0 | goto updateFailed; |
3567 | 0 | } |
3568 | | |
3569 | 0 | if (!sraRgnEmpty(updateCopyRegion)) { |
3570 | 0 | if (!rfbSendCopyRegion(cl,updateCopyRegion,dx,dy)) |
3571 | 0 | goto updateFailed; |
3572 | 0 | } |
3573 | | |
3574 | 0 | for(i = sraRgnGetIterator(updateRegion); sraRgnIteratorNext(i,&rect);){ |
3575 | 0 | int x = rect.x1; |
3576 | 0 | int y = rect.y1; |
3577 | 0 | int w = rect.x2 - x; |
3578 | 0 | int h = rect.y2 - y; |
3579 | | |
3580 | | /* We need to count the number of rects in the scaled screen */ |
3581 | 0 | if (cl->screen!=cl->scaledScreen) |
3582 | 0 | rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate"); |
3583 | |
|
3584 | 0 | switch (cl->preferredEncoding) { |
3585 | 0 | case -1: |
3586 | 0 | case rfbEncodingRaw: |
3587 | 0 | if (!rfbSendRectEncodingRaw(cl, x, y, w, h)) |
3588 | 0 | goto updateFailed; |
3589 | 0 | break; |
3590 | 0 | case rfbEncodingRRE: |
3591 | 0 | if (!rfbSendRectEncodingRRE(cl, x, y, w, h)) |
3592 | 0 | goto updateFailed; |
3593 | 0 | break; |
3594 | 0 | case rfbEncodingCoRRE: |
3595 | 0 | if (!rfbSendRectEncodingCoRRE(cl, x, y, w, h)) |
3596 | 0 | goto updateFailed; |
3597 | 0 | break; |
3598 | 0 | case rfbEncodingHextile: |
3599 | 0 | if (!rfbSendRectEncodingHextile(cl, x, y, w, h)) |
3600 | 0 | goto updateFailed; |
3601 | 0 | break; |
3602 | 0 | case rfbEncodingUltra: |
3603 | 0 | if (!rfbSendRectEncodingUltra(cl, x, y, w, h)) |
3604 | 0 | goto updateFailed; |
3605 | 0 | break; |
3606 | 0 | #ifdef LIBVNCSERVER_HAVE_LIBZ |
3607 | 0 | case rfbEncodingZlib: |
3608 | 0 | if (!rfbSendRectEncodingZlib(cl, x, y, w, h)) |
3609 | 0 | goto updateFailed; |
3610 | 0 | break; |
3611 | 0 | case rfbEncodingZRLE: |
3612 | 0 | case rfbEncodingZYWRLE: |
3613 | 0 | if (!rfbSendRectEncodingZRLE(cl, x, y, w, h)) |
3614 | 0 | goto updateFailed; |
3615 | 0 | break; |
3616 | 0 | #endif |
3617 | | #if defined(LIBVNCSERVER_HAVE_LIBJPEG) && (defined(LIBVNCSERVER_HAVE_LIBZ) || defined(LIBVNCSERVER_HAVE_LIBPNG)) |
3618 | | case rfbEncodingTight: |
3619 | | if (!rfbSendRectEncodingTight(cl, x, y, w, h)) |
3620 | | goto updateFailed; |
3621 | | break; |
3622 | | #ifdef LIBVNCSERVER_HAVE_LIBPNG |
3623 | | case rfbEncodingTightPng: |
3624 | | if (!rfbSendRectEncodingTightPng(cl, x, y, w, h)) |
3625 | | goto updateFailed; |
3626 | | break; |
3627 | | #endif |
3628 | | #endif |
3629 | 0 | } |
3630 | 0 | } |
3631 | 0 | if (i) { |
3632 | 0 | sraRgnReleaseIterator(i); |
3633 | 0 | i = NULL; |
3634 | 0 | } |
3635 | |
|
3636 | 0 | if ( nUpdateRegionRects == 0xFFFF && |
3637 | 0 | !rfbSendLastRectMarker(cl) ) |
3638 | 0 | goto updateFailed; |
3639 | | |
3640 | 0 | if (!rfbSendUpdateBuf(cl)) { |
3641 | 0 | updateFailed: |
3642 | 0 | result = FALSE; |
3643 | 0 | } |
3644 | |
|
3645 | 0 | if (!cl->enableCursorShapeUpdates) { |
3646 | 0 | rfbHideCursor(cl); |
3647 | 0 | } |
3648 | |
|
3649 | 0 | if(i) |
3650 | 0 | sraRgnReleaseIterator(i); |
3651 | 0 | sraRgnDestroy(updateRegion); |
3652 | 0 | sraRgnDestroy(updateCopyRegion); |
3653 | |
|
3654 | 0 | if(cl->screen->displayFinishedHook) |
3655 | 0 | cl->screen->displayFinishedHook(cl, result); |
3656 | 0 | return result; |
3657 | 0 | } |
3658 | | |
3659 | | |
3660 | | /* |
3661 | | * Send the copy region as a string of CopyRect encoded rectangles. |
3662 | | * The only slightly tricky thing is that we should send the messages in |
3663 | | * the correct order so that an earlier CopyRect will not corrupt the source |
3664 | | * of a later one. |
3665 | | */ |
3666 | | |
3667 | | rfbBool |
3668 | | rfbSendCopyRegion(rfbClientPtr cl, |
3669 | | sraRegionPtr reg, |
3670 | | int dx, |
3671 | | int dy) |
3672 | 0 | { |
3673 | 0 | int x, y, w, h; |
3674 | 0 | rfbFramebufferUpdateRectHeader rect; |
3675 | 0 | rfbCopyRect cr; |
3676 | 0 | sraRectangleIterator* i; |
3677 | 0 | sraRect rect1; |
3678 | | |
3679 | | /* printf("copyrect: "); sraRgnPrint(reg); putchar('\n');fflush(stdout); */ |
3680 | 0 | i = sraRgnGetReverseIterator(reg,dx>0,dy>0); |
3681 | | |
3682 | | /* correct for the scale of the screen */ |
3683 | 0 | dx = ScaleX(cl->screen, cl->scaledScreen, dx); |
3684 | 0 | dy = ScaleX(cl->screen, cl->scaledScreen, dy); |
3685 | |
|
3686 | 0 | while(sraRgnIteratorNext(i,&rect1)) { |
3687 | 0 | x = rect1.x1; |
3688 | 0 | y = rect1.y1; |
3689 | 0 | w = rect1.x2 - x; |
3690 | 0 | h = rect1.y2 - y; |
3691 | | |
3692 | | /* correct for scaling (if necessary) */ |
3693 | 0 | rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "copyrect"); |
3694 | |
|
3695 | 0 | rect.r.x = Swap16IfLE(x); |
3696 | 0 | rect.r.y = Swap16IfLE(y); |
3697 | 0 | rect.r.w = Swap16IfLE(w); |
3698 | 0 | rect.r.h = Swap16IfLE(h); |
3699 | 0 | rect.encoding = Swap32IfLE(rfbEncodingCopyRect); |
3700 | |
|
3701 | 0 | memcpy(&cl->updateBuf[cl->ublen], (char *)&rect, |
3702 | 0 | sz_rfbFramebufferUpdateRectHeader); |
3703 | 0 | cl->ublen += sz_rfbFramebufferUpdateRectHeader; |
3704 | |
|
3705 | 0 | cr.srcX = Swap16IfLE(x - dx); |
3706 | 0 | cr.srcY = Swap16IfLE(y - dy); |
3707 | |
|
3708 | 0 | memcpy(&cl->updateBuf[cl->ublen], (char *)&cr, sz_rfbCopyRect); |
3709 | 0 | cl->ublen += sz_rfbCopyRect; |
3710 | |
|
3711 | 0 | rfbStatRecordEncodingSent(cl, rfbEncodingCopyRect, sz_rfbFramebufferUpdateRectHeader + sz_rfbCopyRect, |
3712 | 0 | w * h * (cl->scaledScreen->bitsPerPixel / 8)); |
3713 | 0 | } |
3714 | 0 | sraRgnReleaseIterator(i); |
3715 | |
|
3716 | 0 | return TRUE; |
3717 | 0 | } |
3718 | | |
3719 | | /* |
3720 | | * Send a given rectangle in raw encoding (rfbEncodingRaw). |
3721 | | */ |
3722 | | |
3723 | | rfbBool |
3724 | | rfbSendRectEncodingRaw(rfbClientPtr cl, |
3725 | | int x, |
3726 | | int y, |
3727 | | int w, |
3728 | | int h) |
3729 | 0 | { |
3730 | 0 | rfbFramebufferUpdateRectHeader rect; |
3731 | 0 | int nlines; |
3732 | 0 | int bytesPerLine = w * (cl->format.bitsPerPixel / 8); |
3733 | 0 | char *fbptr = (cl->scaledScreen->frameBuffer + (cl->scaledScreen->paddedWidthInBytes * y) |
3734 | 0 | + (x * (cl->scaledScreen->bitsPerPixel / 8))); |
3735 | |
|
3736 | 0 | if(!h || !w) |
3737 | 0 | return TRUE; /* nothing to send */ |
3738 | | |
3739 | | /* Flush the buffer to guarantee correct alignment for translateFn(). */ |
3740 | 0 | if (cl->ublen > 0) { |
3741 | 0 | if (!rfbSendUpdateBuf(cl)) |
3742 | 0 | return FALSE; |
3743 | 0 | } |
3744 | | |
3745 | 0 | rect.r.x = Swap16IfLE(x); |
3746 | 0 | rect.r.y = Swap16IfLE(y); |
3747 | 0 | rect.r.w = Swap16IfLE(w); |
3748 | 0 | rect.r.h = Swap16IfLE(h); |
3749 | 0 | rect.encoding = Swap32IfLE(rfbEncodingRaw); |
3750 | |
|
3751 | 0 | memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader); |
3752 | 0 | cl->ublen += sz_rfbFramebufferUpdateRectHeader; |
3753 | | |
3754 | |
|
3755 | 0 | rfbStatRecordEncodingSent(cl, rfbEncodingRaw, sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h, |
3756 | 0 | sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h); |
3757 | |
|
3758 | 0 | nlines = (UPDATE_BUF_SIZE - cl->ublen) / bytesPerLine; |
3759 | |
|
3760 | 0 | while (TRUE) { |
3761 | 0 | if (nlines > h) |
3762 | 0 | nlines = h; |
3763 | |
|
3764 | 0 | (*cl->translateFn)(cl->translateLookupTable, |
3765 | 0 | &(cl->screen->serverFormat), |
3766 | 0 | &cl->format, fbptr, &cl->updateBuf[cl->ublen], |
3767 | 0 | cl->scaledScreen->paddedWidthInBytes, w, nlines); |
3768 | |
|
3769 | 0 | cl->ublen += nlines * bytesPerLine; |
3770 | 0 | h -= nlines; |
3771 | |
|
3772 | 0 | if (h == 0) /* rect fitted in buffer, do next one */ |
3773 | 0 | return TRUE; |
3774 | | |
3775 | | /* buffer full - flush partial rect and do another nlines */ |
3776 | | |
3777 | 0 | if (!rfbSendUpdateBuf(cl)) |
3778 | 0 | return FALSE; |
3779 | | |
3780 | 0 | fbptr += (cl->scaledScreen->paddedWidthInBytes * nlines); |
3781 | |
|
3782 | 0 | nlines = (UPDATE_BUF_SIZE - cl->ublen) / bytesPerLine; |
3783 | 0 | if (nlines == 0) { |
3784 | 0 | rfbErr("rfbSendRectEncodingRaw: send buffer too small for %d " |
3785 | 0 | "bytes per line\n", bytesPerLine); |
3786 | 0 | rfbCloseClient(cl); |
3787 | 0 | return FALSE; |
3788 | 0 | } |
3789 | 0 | } |
3790 | 0 | } |
3791 | | |
3792 | | |
3793 | | |
3794 | | /* |
3795 | | * Send an empty rectangle with encoding field set to value of |
3796 | | * rfbEncodingLastRect to notify client that this is the last |
3797 | | * rectangle in framebuffer update ("LastRect" extension of RFB |
3798 | | * protocol). |
3799 | | */ |
3800 | | |
3801 | | rfbBool |
3802 | | rfbSendLastRectMarker(rfbClientPtr cl) |
3803 | 0 | { |
3804 | 0 | rfbFramebufferUpdateRectHeader rect; |
3805 | |
|
3806 | 0 | if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) { |
3807 | 0 | if (!rfbSendUpdateBuf(cl)) |
3808 | 0 | return FALSE; |
3809 | 0 | } |
3810 | | |
3811 | 0 | rect.encoding = Swap32IfLE(rfbEncodingLastRect); |
3812 | 0 | rect.r.x = 0; |
3813 | 0 | rect.r.y = 0; |
3814 | 0 | rect.r.w = 0; |
3815 | 0 | rect.r.h = 0; |
3816 | |
|
3817 | 0 | memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader); |
3818 | 0 | cl->ublen += sz_rfbFramebufferUpdateRectHeader; |
3819 | | |
3820 | |
|
3821 | 0 | rfbStatRecordEncodingSent(cl, rfbEncodingLastRect, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader); |
3822 | |
|
3823 | 0 | return TRUE; |
3824 | 0 | } |
3825 | | |
3826 | | |
3827 | | /* |
3828 | | * Send NewFBSize pseudo-rectangle. This tells the client to change |
3829 | | * its framebuffer size. |
3830 | | */ |
3831 | | |
3832 | | rfbBool |
3833 | | rfbSendNewFBSize(rfbClientPtr cl, |
3834 | | int w, |
3835 | | int h) |
3836 | 0 | { |
3837 | 0 | rfbFramebufferUpdateRectHeader rect; |
3838 | |
|
3839 | 0 | if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) { |
3840 | 0 | if (!rfbSendUpdateBuf(cl)) |
3841 | 0 | return FALSE; |
3842 | 0 | } |
3843 | | |
3844 | 0 | if (cl->PalmVNC==TRUE) |
3845 | 0 | rfbLog("Sending rfbEncodingNewFBSize in response to a PalmVNC style framebuffer resize (%dx%d)\n", w, h); |
3846 | 0 | else |
3847 | 0 | rfbLog("Sending rfbEncodingNewFBSize for resize to (%dx%d)\n", w, h); |
3848 | |
|
3849 | 0 | rect.encoding = Swap32IfLE(rfbEncodingNewFBSize); |
3850 | 0 | rect.r.x = 0; |
3851 | 0 | rect.r.y = 0; |
3852 | 0 | rect.r.w = Swap16IfLE(w); |
3853 | 0 | rect.r.h = Swap16IfLE(h); |
3854 | |
|
3855 | 0 | memcpy(&cl->updateBuf[cl->ublen], (char *)&rect, |
3856 | 0 | sz_rfbFramebufferUpdateRectHeader); |
3857 | 0 | cl->ublen += sz_rfbFramebufferUpdateRectHeader; |
3858 | |
|
3859 | 0 | rfbStatRecordEncodingSent(cl, rfbEncodingNewFBSize, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader); |
3860 | |
|
3861 | 0 | return TRUE; |
3862 | 0 | } |
3863 | | |
3864 | | /* |
3865 | | * Send ExtDesktopSize pseudo-rectangle. This message is used: |
3866 | | * - to tell the client to change its framebuffer size |
3867 | | * - at the start of the session to inform the client we support size changes through setDesktopSize |
3868 | | * - in response to setDesktopSize commands to indicate success or failure |
3869 | | */ |
3870 | | |
3871 | | rfbBool |
3872 | | rfbSendExtDesktopSize(rfbClientPtr cl, |
3873 | | int w, |
3874 | | int h) |
3875 | 0 | { |
3876 | 0 | rfbFramebufferUpdateRectHeader rect; |
3877 | 0 | rfbExtDesktopSizeMsg edsHdr; |
3878 | 0 | rfbExtDesktopScreen eds; |
3879 | 0 | int i; |
3880 | 0 | char *logmsg; |
3881 | 0 | int numScreens = cl->screen->numberOfExtDesktopScreensHook(cl); |
3882 | |
|
3883 | 0 | if (cl->ublen + sz_rfbFramebufferUpdateRectHeader |
3884 | 0 | + sz_rfbExtDesktopSizeMsg |
3885 | 0 | + sz_rfbExtDesktopScreen * numScreens > UPDATE_BUF_SIZE) { |
3886 | 0 | if (!rfbSendUpdateBuf(cl)) |
3887 | 0 | return FALSE; |
3888 | 0 | } |
3889 | | |
3890 | 0 | rect.encoding = Swap32IfLE(rfbEncodingExtDesktopSize); |
3891 | 0 | rect.r.w = Swap16IfLE(w); |
3892 | 0 | rect.r.h = Swap16IfLE(h); |
3893 | 0 | rect.r.x = Swap16IfLE(cl->requestedDesktopSizeChange); |
3894 | 0 | rect.r.y = Swap16IfLE(cl->lastDesktopSizeChangeError); |
3895 | |
|
3896 | 0 | logmsg = ""; |
3897 | |
|
3898 | 0 | if (cl->requestedDesktopSizeChange == rfbExtDesktopSize_ClientRequestedChange) |
3899 | 0 | { |
3900 | | /* our client requested the resize through setDesktopSize */ |
3901 | |
|
3902 | 0 | switch (cl->lastDesktopSizeChangeError) |
3903 | 0 | { |
3904 | 0 | case rfbExtDesktopSize_Success: |
3905 | 0 | logmsg = "resize successful"; |
3906 | 0 | break; |
3907 | 0 | case rfbExtDesktopSize_ResizeProhibited: |
3908 | 0 | logmsg = "resize prohibited"; |
3909 | 0 | break; |
3910 | 0 | case rfbExtDesktopSize_OutOfResources: |
3911 | 0 | logmsg = "resize failed: out of resources"; |
3912 | 0 | break; |
3913 | 0 | case rfbExtDesktopSize_InvalidScreenLayout: |
3914 | 0 | logmsg = "resize failed: invalid screen layout"; |
3915 | 0 | break; |
3916 | 0 | default: |
3917 | 0 | break; |
3918 | 0 | } |
3919 | 0 | } |
3920 | | |
3921 | 0 | cl->requestedDesktopSizeChange = 0; |
3922 | 0 | cl->lastDesktopSizeChangeError = 0; |
3923 | |
|
3924 | 0 | rfbLog("Sending rfbEncodingExtDesktopSize for size (%dx%d) %s\n", w, h, logmsg); |
3925 | |
|
3926 | 0 | memcpy(&cl->updateBuf[cl->ublen], (char *)&rect, |
3927 | 0 | sz_rfbFramebufferUpdateRectHeader); |
3928 | 0 | cl->ublen += sz_rfbFramebufferUpdateRectHeader; |
3929 | |
|
3930 | 0 | edsHdr.numberOfScreens = numScreens; |
3931 | 0 | edsHdr.pad[0] = edsHdr.pad[1] = edsHdr.pad[2] = 0; |
3932 | 0 | memcpy(&cl->updateBuf[cl->ublen], (char *)&edsHdr, |
3933 | 0 | sz_rfbExtDesktopSizeMsg); |
3934 | 0 | cl->ublen += sz_rfbExtDesktopSizeMsg; |
3935 | |
|
3936 | 0 | for (i=0; i<numScreens; i++) { |
3937 | 0 | if (!cl->screen->getExtDesktopScreenHook(i, &eds, cl)) |
3938 | 0 | { |
3939 | 0 | rfbErr("Error getting ExtendedDesktopSize information for screen #%d\n", i); |
3940 | 0 | return FALSE; |
3941 | 0 | } |
3942 | 0 | eds.id = Swap32IfLE(eds.id); |
3943 | 0 | eds.x = Swap16IfLE(eds.x); |
3944 | 0 | eds.y = Swap16IfLE(eds.y); |
3945 | 0 | eds.width = Swap16IfLE(eds.width); |
3946 | 0 | eds.height = Swap16IfLE(eds.height); |
3947 | 0 | eds.flags = Swap32IfLE(eds.flags); |
3948 | 0 | memcpy(&cl->updateBuf[cl->ublen], (char *)&eds, |
3949 | 0 | sz_rfbExtDesktopScreen); |
3950 | 0 | cl->ublen += sz_rfbExtDesktopScreen; |
3951 | 0 | } |
3952 | | |
3953 | 0 | rfbStatRecordEncodingSent(cl, rfbEncodingExtDesktopSize, |
3954 | 0 | sz_rfbFramebufferUpdateRectHeader + sz_rfbExtDesktopSizeMsg + sz_rfbExtDesktopScreen * numScreens, |
3955 | 0 | sz_rfbFramebufferUpdateRectHeader + sz_rfbExtDesktopSizeMsg + sz_rfbExtDesktopScreen * numScreens); |
3956 | |
|
3957 | 0 | return TRUE; |
3958 | 0 | } |
3959 | | |
3960 | | /* |
3961 | | * Send the contents of cl->updateBuf. Returns 1 if successful, -1 if |
3962 | | * not (errno should be set). |
3963 | | */ |
3964 | | |
3965 | | rfbBool |
3966 | | rfbSendUpdateBuf(rfbClientPtr cl) |
3967 | 0 | { |
3968 | 0 | if(cl->sock<0) |
3969 | 0 | return FALSE; |
3970 | | |
3971 | 0 | if (rfbWriteExact(cl, cl->updateBuf, cl->ublen) < 0) { |
3972 | 0 | rfbLogPerror("rfbSendUpdateBuf: write"); |
3973 | 0 | rfbCloseClient(cl); |
3974 | 0 | return FALSE; |
3975 | 0 | } |
3976 | | |
3977 | 0 | cl->ublen = 0; |
3978 | 0 | return TRUE; |
3979 | 0 | } |
3980 | | |
3981 | | /* |
3982 | | * rfbSendSetColourMapEntries sends a SetColourMapEntries message to the |
3983 | | * client, using values from the currently installed colormap. |
3984 | | */ |
3985 | | |
3986 | | rfbBool |
3987 | | rfbSendSetColourMapEntries(rfbClientPtr cl, |
3988 | | int firstColour, |
3989 | | int nColours) |
3990 | 0 | { |
3991 | 0 | char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2]; |
3992 | 0 | char *wbuf = buf; |
3993 | 0 | rfbSetColourMapEntriesMsg *scme; |
3994 | 0 | uint16_t *rgb; |
3995 | 0 | rfbColourMap* cm = &cl->screen->colourMap; |
3996 | 0 | int i, len; |
3997 | |
|
3998 | 0 | if (nColours > 256) { |
3999 | | /* some rare hardware has, e.g., 4096 colors cells: PseudoColor:12 */ |
4000 | 0 | wbuf = (char *) malloc(sz_rfbSetColourMapEntriesMsg + nColours * 3 * 2); |
4001 | 0 | } |
4002 | |
|
4003 | 0 | scme = (rfbSetColourMapEntriesMsg *)wbuf; |
4004 | 0 | rgb = (uint16_t *)(&wbuf[sz_rfbSetColourMapEntriesMsg]); |
4005 | |
|
4006 | 0 | scme->type = rfbSetColourMapEntries; |
4007 | |
|
4008 | 0 | scme->firstColour = Swap16IfLE(firstColour); |
4009 | 0 | scme->nColours = Swap16IfLE(nColours); |
4010 | |
|
4011 | 0 | len = sz_rfbSetColourMapEntriesMsg; |
4012 | |
|
4013 | 0 | for (i = 0; i < nColours; i++) { |
4014 | 0 | if(i<(int)cm->count) { |
4015 | 0 | if(cm->is16) { |
4016 | 0 | rgb[i*3] = Swap16IfLE(cm->data.shorts[i*3]); |
4017 | 0 | rgb[i*3+1] = Swap16IfLE(cm->data.shorts[i*3+1]); |
4018 | 0 | rgb[i*3+2] = Swap16IfLE(cm->data.shorts[i*3+2]); |
4019 | 0 | } else { |
4020 | 0 | rgb[i*3] = Swap16IfLE((unsigned short)cm->data.bytes[i*3]); |
4021 | 0 | rgb[i*3+1] = Swap16IfLE((unsigned short)cm->data.bytes[i*3+1]); |
4022 | 0 | rgb[i*3+2] = Swap16IfLE((unsigned short)cm->data.bytes[i*3+2]); |
4023 | 0 | } |
4024 | 0 | } |
4025 | 0 | } |
4026 | |
|
4027 | 0 | len += nColours * 3 * 2; |
4028 | |
|
4029 | 0 | LOCK(cl->sendMutex); |
4030 | 0 | if (rfbWriteExact(cl, wbuf, len) < 0) { |
4031 | 0 | rfbLogPerror("rfbSendSetColourMapEntries: write"); |
4032 | 0 | rfbCloseClient(cl); |
4033 | 0 | if (wbuf != buf) free(wbuf); |
4034 | 0 | UNLOCK(cl->sendMutex); |
4035 | 0 | return FALSE; |
4036 | 0 | } |
4037 | 0 | UNLOCK(cl->sendMutex); |
4038 | |
|
4039 | 0 | rfbStatRecordMessageSent(cl, rfbSetColourMapEntries, len, len); |
4040 | 0 | if (wbuf != buf) free(wbuf); |
4041 | 0 | return TRUE; |
4042 | 0 | } |
4043 | | |
4044 | | /* |
4045 | | * rfbSendBell sends a Bell message to all the clients. |
4046 | | */ |
4047 | | |
4048 | | void |
4049 | | rfbSendBell(rfbScreenInfoPtr rfbScreen) |
4050 | 0 | { |
4051 | 0 | rfbClientIteratorPtr i; |
4052 | 0 | rfbClientPtr cl; |
4053 | 0 | rfbBellMsg b; |
4054 | |
|
4055 | 0 | i = rfbGetClientIterator(rfbScreen); |
4056 | 0 | while((cl=rfbClientIteratorNext(i))) { |
4057 | 0 | b.type = rfbBell; |
4058 | 0 | LOCK(cl->sendMutex); |
4059 | 0 | if (rfbWriteExact(cl, (char *)&b, sz_rfbBellMsg) < 0) { |
4060 | 0 | rfbLogPerror("rfbSendBell: write"); |
4061 | 0 | rfbCloseClient(cl); |
4062 | 0 | } |
4063 | 0 | UNLOCK(cl->sendMutex); |
4064 | 0 | } |
4065 | 0 | rfbStatRecordMessageSent(cl, rfbBell, sz_rfbBellMsg, sz_rfbBellMsg); |
4066 | 0 | rfbReleaseClientIterator(i); |
4067 | 0 | } |
4068 | | |
4069 | | |
4070 | | /* |
4071 | | * rfbSendServerCutText sends a ServerCutText message to all the clients. |
4072 | | */ |
4073 | | |
4074 | | void |
4075 | | rfbSendServerCutText(rfbScreenInfoPtr rfbScreen,char *str, int len) |
4076 | 0 | { |
4077 | 0 | rfbClientPtr cl; |
4078 | 0 | rfbServerCutTextMsg sct; |
4079 | 0 | rfbClientIteratorPtr iterator; |
4080 | |
|
4081 | 0 | memset((char *)&sct, 0, sizeof(sct)); |
4082 | |
|
4083 | 0 | iterator = rfbGetClientIterator(rfbScreen); |
4084 | 0 | while ((cl = rfbClientIteratorNext(iterator)) != NULL) { |
4085 | 0 | sct.type = rfbServerCutText; |
4086 | 0 | sct.length = Swap32IfLE(len); |
4087 | 0 | LOCK(cl->sendMutex); |
4088 | 0 | if (rfbWriteExact(cl, (char *)&sct, |
4089 | 0 | sz_rfbServerCutTextMsg) < 0) { |
4090 | 0 | rfbLogPerror("rfbSendServerCutText: write"); |
4091 | 0 | rfbCloseClient(cl); |
4092 | 0 | UNLOCK(cl->sendMutex); |
4093 | 0 | continue; |
4094 | 0 | } |
4095 | 0 | if (rfbWriteExact(cl, str, len) < 0) { |
4096 | 0 | rfbLogPerror("rfbSendServerCutText: write"); |
4097 | 0 | rfbCloseClient(cl); |
4098 | 0 | } |
4099 | 0 | UNLOCK(cl->sendMutex); |
4100 | 0 | rfbStatRecordMessageSent(cl, rfbServerCutText, sz_rfbServerCutTextMsg+len, sz_rfbServerCutTextMsg+len); |
4101 | 0 | } |
4102 | 0 | rfbReleaseClientIterator(iterator); |
4103 | 0 | } |
4104 | | |
4105 | | #ifdef LIBVNCSERVER_HAVE_LIBZ |
4106 | | void |
4107 | | rfbSendServerCutTextUTF8(rfbScreenInfoPtr rfbScreen,char *str, int len, char *fallbackLatin1Str, int latin1Len) |
4108 | 0 | { |
4109 | 0 | rfbClientPtr cl; |
4110 | 0 | rfbServerCutTextMsg sct; |
4111 | 0 | rfbClientIteratorPtr iterator; |
4112 | |
|
4113 | 0 | memset((char *)&sct, 0, sizeof(sct)); |
4114 | |
|
4115 | 0 | iterator = rfbGetClientIterator(rfbScreen); |
4116 | 0 | while ((cl = rfbClientIteratorNext(iterator)) != NULL) { |
4117 | 0 | sct.type = rfbServerCutText; |
4118 | 0 | LOCK(cl->sendMutex); |
4119 | 0 | if (cl->enableExtendedClipboard) { |
4120 | 0 | sct.length = Swap32IfLE(len); |
4121 | 0 | if (cl->extClipboardData != NULL) { |
4122 | 0 | free(cl->extClipboardData); |
4123 | 0 | cl->extClipboardData = NULL; |
4124 | 0 | } |
4125 | 0 | cl->extClipboardData = (char *)malloc(len + 1); |
4126 | 0 | if (cl->extClipboardData == NULL) { |
4127 | 0 | rfbLogPerror("rfbSendServerCutText: failed to allocate memory"); |
4128 | 0 | rfbCloseClient(cl); |
4129 | 0 | UNLOCK(cl->sendMutex); |
4130 | 0 | continue; |
4131 | 0 | } |
4132 | 0 | cl->extClipboardDataSize = len + 1; |
4133 | 0 | memcpy(cl->extClipboardData, str, len); |
4134 | 0 | cl->extClipboardData[len] = 0; /* null terminated */ |
4135 | 0 | if ((cl->extClipboardUserCap & rfbExtendedClipboard_Provide) && len <= cl->extClipboardMaxUnsolicitedSize) { |
4136 | 0 | if (!rfbSendExtendedServerCutTextData(cl, cl->extClipboardData, len + 1)) { |
4137 | 0 | UNLOCK(cl->sendMutex); |
4138 | 0 | continue; |
4139 | 0 | } |
4140 | 0 | } else if (cl->extClipboardUserCap & rfbExtendedClipboard_Notify) { |
4141 | 0 | if (!rfbSendExtendedClipboardNotify(cl)) { |
4142 | 0 | UNLOCK(cl->sendMutex); |
4143 | 0 | continue; |
4144 | 0 | } |
4145 | 0 | } |
4146 | 0 | UNLOCK(cl->sendMutex); |
4147 | 0 | } else if (fallbackLatin1Str != NULL) { |
4148 | 0 | sct.length = Swap32IfLE(latin1Len); |
4149 | 0 | if (rfbWriteExact(cl, (char *)&sct, |
4150 | 0 | sz_rfbServerCutTextMsg) < 0) { |
4151 | 0 | rfbLogPerror("rfbSendServerCutText: write"); |
4152 | 0 | rfbCloseClient(cl); |
4153 | 0 | UNLOCK(cl->sendMutex); |
4154 | 0 | continue; |
4155 | 0 | } |
4156 | 0 | if (rfbWriteExact(cl, fallbackLatin1Str, latin1Len) < 0) { |
4157 | 0 | rfbLogPerror("rfbSendServerCutText: write"); |
4158 | 0 | rfbCloseClient(cl); |
4159 | 0 | } |
4160 | 0 | UNLOCK(cl->sendMutex); |
4161 | 0 | rfbStatRecordMessageSent(cl, rfbServerCutText, sz_rfbServerCutTextMsg+len, sz_rfbServerCutTextMsg+len); |
4162 | 0 | } |
4163 | 0 | } |
4164 | 0 | rfbReleaseClientIterator(iterator); |
4165 | 0 | } |
4166 | | #endif |
4167 | | |
4168 | | /***************************************************************************** |
4169 | | * |
4170 | | * UDP can be used for keyboard and pointer events when the underlying |
4171 | | * network is highly reliable. This is really here to support ORL's |
4172 | | * videotile, whose TCP implementation doesn't like sending lots of small |
4173 | | * packets (such as 100s of pen readings per second!). |
4174 | | */ |
4175 | | |
4176 | | static unsigned char ptrAcceleration = 50; |
4177 | | |
4178 | | void |
4179 | | rfbNewUDPConnection(rfbScreenInfoPtr rfbScreen, |
4180 | | rfbSocket sock) |
4181 | 0 | { |
4182 | 0 | if (write(sock, (char*) &ptrAcceleration, 1) < 0) { |
4183 | 0 | rfbLogPerror("rfbNewUDPConnection: write"); |
4184 | 0 | } |
4185 | 0 | } |
4186 | | |
4187 | | /* |
4188 | | * Because UDP is a message based service, we can't read the first byte and |
4189 | | * then the rest of the packet separately like we do with TCP. We will always |
4190 | | * get a whole packet delivered in one go, so we ask read() for the maximum |
4191 | | * number of bytes we can possibly get. |
4192 | | */ |
4193 | | |
4194 | | void |
4195 | | rfbProcessUDPInput(rfbScreenInfoPtr rfbScreen) |
4196 | 0 | { |
4197 | 0 | int n; |
4198 | 0 | rfbClientPtr cl=rfbScreen->udpClient; |
4199 | 0 | rfbClientToServerMsg msg; |
4200 | |
|
4201 | 0 | if((!cl) || cl->onHold) |
4202 | 0 | return; |
4203 | | |
4204 | 0 | if ((n = read(rfbScreen->udpSock, (char *)&msg, sizeof(msg))) <= 0) { |
4205 | 0 | if (n < 0) { |
4206 | 0 | rfbLogPerror("rfbProcessUDPInput: read"); |
4207 | 0 | } |
4208 | 0 | rfbDisconnectUDPSock(rfbScreen); |
4209 | 0 | return; |
4210 | 0 | } |
4211 | | |
4212 | 0 | switch (msg.type) { |
4213 | | |
4214 | 0 | case rfbKeyEvent: |
4215 | 0 | if (n != sz_rfbKeyEventMsg) { |
4216 | 0 | rfbErr("rfbProcessUDPInput: key event incorrect length\n"); |
4217 | 0 | rfbDisconnectUDPSock(rfbScreen); |
4218 | 0 | return; |
4219 | 0 | } |
4220 | 0 | cl->screen->kbdAddEvent(msg.ke.down, (rfbKeySym)Swap32IfLE(msg.ke.key), cl); |
4221 | 0 | break; |
4222 | | |
4223 | 0 | case rfbPointerEvent: |
4224 | 0 | if (n != sz_rfbPointerEventMsg) { |
4225 | 0 | rfbErr("rfbProcessUDPInput: ptr event incorrect length\n"); |
4226 | 0 | rfbDisconnectUDPSock(rfbScreen); |
4227 | 0 | return; |
4228 | 0 | } |
4229 | 0 | cl->screen->ptrAddEvent(msg.pe.buttonMask, |
4230 | 0 | Swap16IfLE(msg.pe.x), Swap16IfLE(msg.pe.y), cl); |
4231 | 0 | break; |
4232 | | |
4233 | 0 | default: |
4234 | 0 | rfbErr("rfbProcessUDPInput: unknown message type %d\n", |
4235 | 0 | msg.type); |
4236 | 0 | rfbDisconnectUDPSock(rfbScreen); |
4237 | 0 | } |
4238 | 0 | } |
4239 | | |
4240 | | |