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