]> git.sesse.net Git - rdpsrv/blob - Xserver/programs/Xserver/hw/vnc/rfbserver.c
Support RDP5 logon packets.
[rdpsrv] / Xserver / programs / Xserver / hw / vnc / rfbserver.c
1 /*
2  * rfbserver.c - deal with server-side of the RFB protocol.
3  */
4
5 /*
6  *  Copyright (C) 2002-2003 RealVNC Ltd.
7  *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
8  *
9  *  This is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This software is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this software; if not, write to the Free Software
21  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
22  *  USA.
23  */
24
25 /* Use ``#define CORBA'' to enable CORBA control interface */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <pwd.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35 #include "windowstr.h"
36 #include "rfb.h"
37 #include "input.h"
38 #include "mipointer.h"
39 #include "sprite.h"
40
41 #ifdef CORBA
42 #include <vncserverctrl.h>
43 #endif
44
45 char updateBuf[UPDATE_BUF_SIZE];
46 int ublen;
47
48 rfbClientPtr rfbClientHead = NULL;
49 rfbClientPtr pointerClient = NULL;  /* Mutex for pointer events */
50
51 Bool rfbAlwaysShared = FALSE;
52 Bool rfbNeverShared = FALSE;
53 Bool rfbDontDisconnect = FALSE;
54 int rfbMaxRects = 50;
55
56 static rfbClientPtr rfbNewClient(int sock);
57 static void rfbProcessClientProtocolVersion(rfbClientPtr cl);
58 static void rfbProcessClientNormalMessage(rfbClientPtr cl);
59 static void rfbProcessClientInitMessage(rfbClientPtr cl);
60 static Bool rfbSendCopyRegion(rfbClientPtr cl, RegionPtr reg, int dx, int dy);
61
62
63 /*
64  * rfbNewClientConnection is called from sockets.c when a new connection
65  * comes in.
66  */
67
68 void
69 rfbNewClientConnection(sock)
70     int sock;
71 {
72     rfbClientPtr cl;
73
74     cl = rfbNewClient(sock);
75
76 #ifdef CORBA
77     if (cl != NULL)
78         newConnection(cl, (KEYBOARD_DEVICE|POINTER_DEVICE), 1, 1, 1);
79 #endif
80 }
81
82
83 /*
84  * rfbReverseConnection is called by the CORBA stuff to make an outward
85  * connection to a "listening" RFB client.
86  */
87
88 rfbClientPtr
89 rfbReverseConnection(host, port)
90     char *host;
91     int port;
92 {
93     int sock;
94     rfbClientPtr cl;
95
96     if ((sock = rfbConnect(host, port)) < 0)
97         return (rfbClientPtr)NULL;
98
99     cl = rfbNewClient(sock);
100
101     if (cl) {
102         cl->reverseConnection = TRUE;
103     }
104
105     return cl;
106 }
107
108
109 /*
110  * rfbNewClient is called when a new connection has been made by whatever
111  * means.
112  */
113
114 static rfbClientPtr
115 rfbNewClient(sock)
116     int sock;
117 {
118     rfbProtocolVersionMsg pv;
119     rfbClientPtr cl;
120     BoxRec box;
121     struct sockaddr_in addr;
122     unsigned int addrlen = sizeof(struct sockaddr_in);
123
124     if (rfbClientHead == NULL) {
125         /* no other clients - make sure we don't think any keys are pressed */
126         KbdReleaseAllKeys();
127     } else {
128         rfbLog("  (other clients");
129         for (cl = rfbClientHead; cl; cl = cl->next) {
130             fprintf(stderr," %s",cl->host);
131         }
132         fprintf(stderr,")\n");
133     }
134
135     cl = (rfbClientPtr)xalloc(sizeof(rfbClientRec));
136
137     cl->sock = sock;
138     getpeername(sock, (struct sockaddr *)&addr, &addrlen);
139     cl->host = strdup(inet_ntoa(addr.sin_addr));
140
141     cl->state = RFB_PROTOCOL_VERSION;
142
143     cl->reverseConnection = FALSE;
144     cl->readyForSetColourMapEntries = FALSE;
145     cl->useCopyRect = FALSE;
146     cl->preferredEncoding = rfbEncodingRaw;
147     cl->correMaxWidth = 48;
148     cl->correMaxHeight = 48;
149     cl->zrleData = 0;
150
151     REGION_INIT(pScreen,&cl->copyRegion,NullBox,0);
152     cl->copyDX = 0;
153     cl->copyDY = 0;
154
155     box.x1 = box.y1 = 0;
156     box.x2 = rfbScreen.width;
157     box.y2 = rfbScreen.height;
158     REGION_INIT(pScreen,&cl->modifiedRegion,&box,0);
159
160     REGION_INIT(pScreen,&cl->requestedRegion,NullBox,0);
161
162     cl->deferredUpdateScheduled = FALSE;
163     cl->deferredUpdateTimer = NULL;
164
165     cl->format = rfbServerFormat;
166     cl->translateFn = rfbTranslateNone;
167     cl->translateLookupTable = NULL;
168
169     cl->next = rfbClientHead;
170     rfbClientHead = cl;
171
172     rfbResetStats(cl);
173
174     sprintf(pv,rfbProtocolVersionFormat,rfbProtocolMajorVersion,
175             rfbProtocolMinorVersion);
176
177     if (WriteExact(sock, pv, sz_rfbProtocolVersionMsg) < 0) {
178         rfbLogPerror("rfbNewClient: write");
179         rfbCloseSock(sock);
180         return NULL;
181     }
182
183     return cl;
184 }
185
186
187 /*
188  * rfbClientConnectionGone is called from sockets.c just after a connection
189  * has gone away.
190  */
191
192 void
193 rfbClientConnectionGone(sock)
194     int sock;
195 {
196     rfbClientPtr cl, prev;
197
198     for (prev = NULL, cl = rfbClientHead; cl; prev = cl, cl = cl->next) {
199         if (sock == cl->sock)
200             break;
201     }
202
203     if (!cl) {
204         rfbLog("rfbClientConnectionGone: unknown socket %d\n",sock);
205         return;
206     }
207
208     rfbLog("Client %s gone\n",cl->host);
209     free(cl->host);
210
211     if (pointerClient == cl)
212         pointerClient = NULL;
213
214 #ifdef CORBA
215     destroyConnection(cl);
216 #endif
217
218     if (prev)
219         prev->next = cl->next;
220     else
221         rfbClientHead = cl->next;
222
223     FreeZrleData(cl);
224     REGION_UNINIT(pScreen,&cl->copyRegion);
225     REGION_UNINIT(pScreen,&cl->modifiedRegion);
226     TimerFree(cl->deferredUpdateTimer);
227
228     rfbPrintStats(cl);
229
230     if (cl->translateLookupTable) free(cl->translateLookupTable);
231
232     xfree(cl);
233 }
234
235
236 /*
237  * rfbProcessClientMessage is called when there is data to read from a client.
238  */
239
240 void
241 rfbProcessClientMessage(sock)
242     int sock;
243 {
244     rfbClientPtr cl;
245
246     for (cl = rfbClientHead; cl; cl = cl->next) {
247         if (sock == cl->sock)
248             break;
249     }
250
251     if (!cl) {
252         rfbLog("rfbProcessClientMessage: unknown socket %d\n",sock);
253         rfbCloseSock(sock);
254         return;
255     }
256
257 #ifdef CORBA
258     if (isClosePending(cl)) {
259         rfbLog("Closing connection to client %s\n", cl->host);
260         rfbCloseSock(sock);
261         return;
262     }
263 #endif
264
265     switch (cl->state) {
266     case RFB_PROTOCOL_VERSION:
267         rfbProcessClientProtocolVersion(cl);
268         return;
269     case RFB_AUTHENTICATION:
270         rfbAuthProcessClientMessage(cl);
271         return;
272     case RFB_INITIALISATION:
273         rfbProcessClientInitMessage(cl);
274         return;
275     default:
276         rfbProcessClientNormalMessage(cl);
277         return;
278     }
279 }
280
281
282 /*
283  * rfbProcessClientProtocolVersion is called when the client sends its
284  * protocol version.
285  */
286
287 static void
288 rfbProcessClientProtocolVersion(cl)
289     rfbClientPtr cl;
290 {
291     rfbProtocolVersionMsg pv;
292     int n, major, minor;
293     char failureReason[256];
294
295     if ((n = ReadExact(cl->sock, pv, sz_rfbProtocolVersionMsg)) <= 0) {
296         if (n == 0)
297             rfbLog("rfbProcessClientProtocolVersion: client gone\n");
298         else
299             rfbLogPerror("rfbProcessClientProtocolVersion: read");
300         rfbCloseSock(cl->sock);
301         return;
302     }
303
304     pv[sz_rfbProtocolVersionMsg] = 0;
305     if (sscanf(pv,rfbProtocolVersionFormat,&major,&minor) != 2) {
306         rfbLog("rfbProcessClientProtocolVersion: not a valid RFB client\n");
307         rfbCloseSock(cl->sock);
308         return;
309     }
310     rfbLog("Protocol version %d.%d\n", major, minor);
311
312     if (major != rfbProtocolMajorVersion) {
313         /* Major version mismatch - send a ConnFailed message */
314
315         rfbLog("Major version mismatch\n");
316         sprintf(failureReason,
317                 "RFB protocol version mismatch - server %d.%d, client %d.%d",
318                 rfbProtocolMajorVersion,rfbProtocolMinorVersion,major,minor);
319         rfbClientConnFailed(cl, failureReason);
320         return;
321     }
322
323     if (minor != rfbProtocolMinorVersion) {
324         /* Minor version mismatch - warn but try to continue */
325         rfbLog("Ignoring minor version mismatch\n");
326     }
327
328     rfbAuthNewClient(cl);
329 }
330
331
332 /*
333  * rfbClientConnFailed is called when a client connection has failed either
334  * because it talks the wrong protocol or it has failed authentication.
335  */
336
337 void
338 rfbClientConnFailed(cl, reason)
339     rfbClientPtr cl;
340     char *reason;
341 {
342     char *buf;
343     int len = strlen(reason);
344
345     buf = (char *)xalloc(8 + len);
346     ((CARD32 *)buf)[0] = Swap32IfLE(rfbConnFailed);
347     ((CARD32 *)buf)[1] = Swap32IfLE(len);
348     memcpy(buf + 8, reason, len);
349
350     if (WriteExact(cl->sock, buf, 8 + len) < 0)
351         rfbLogPerror("rfbClientConnFailed: write");
352     xfree(buf);
353     rfbCloseSock(cl->sock);
354 }
355
356
357 /*
358  * rfbProcessClientInitMessage is called when the client sends its
359  * initialisation message.
360  */
361
362 static void
363 rfbProcessClientInitMessage(cl)
364     rfbClientPtr cl;
365 {
366     rfbClientInitMsg ci;
367     char buf[256];
368     rfbServerInitMsg *si = (rfbServerInitMsg *)buf;
369     struct passwd *user;
370     int len, n;
371     rfbClientPtr otherCl, nextCl;
372
373     if ((n = ReadExact(cl->sock, (char *)&ci,sz_rfbClientInitMsg)) <= 0) {
374         if (n == 0)
375             rfbLog("rfbProcessClientInitMessage: client gone\n");
376         else
377             rfbLogPerror("rfbProcessClientInitMessage: read");
378         rfbCloseSock(cl->sock);
379         return;
380     }
381
382     si->framebufferWidth = Swap16IfLE(rfbScreen.width);
383     si->framebufferHeight = Swap16IfLE(rfbScreen.height);
384     si->format = rfbServerFormat;
385     si->format.redMax = Swap16IfLE(si->format.redMax);
386     si->format.greenMax = Swap16IfLE(si->format.greenMax);
387     si->format.blueMax = Swap16IfLE(si->format.blueMax);
388
389     user = getpwuid(getuid());
390
391     if (strlen(desktopName) > 128)      /* sanity check on desktop name len */
392         desktopName[128] = 0;
393
394     if (user) {
395         sprintf(buf + sz_rfbServerInitMsg, "%s's %s desktop (%s:%s)",
396                 user->pw_name, desktopName, rfbThisHost, display);
397     } else {
398         sprintf(buf + sz_rfbServerInitMsg, "%s desktop (%s:%s)",
399                 desktopName, rfbThisHost, display);
400     }
401     len = strlen(buf + sz_rfbServerInitMsg);
402     si->nameLength = Swap32IfLE(len);
403
404     if (WriteExact(cl->sock, buf, sz_rfbServerInitMsg + len) < 0) {
405         rfbLogPerror("rfbProcessClientInitMessage: write");
406         rfbCloseSock(cl->sock);
407         return;
408     }
409
410     cl->state = RFB_NORMAL;
411
412     if (!cl->reverseConnection &&
413                         (rfbNeverShared || (!rfbAlwaysShared && !ci.shared))) {
414
415         if (rfbDontDisconnect) {
416             for (otherCl = rfbClientHead; otherCl; otherCl = otherCl->next) {
417                 if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) {
418                     rfbLog("-dontdisconnect: Not shared & existing client\n");
419                     rfbLog("  refusing new client %s\n", cl->host);
420                     rfbCloseSock(cl->sock);
421                     return;
422                 }
423             }
424         } else {
425             for (otherCl = rfbClientHead; otherCl; otherCl = nextCl) {
426                 nextCl = otherCl->next;
427                 if ((otherCl != cl) && (otherCl->state == RFB_NORMAL)) {
428                     rfbLog("Not shared - closing connection to client %s\n",
429                            otherCl->host);
430                     rfbCloseSock(otherCl->sock);
431                 }
432             }
433         }
434     }
435 }
436
437
438 /*
439  * rfbProcessClientNormalMessage is called when the client has sent a normal
440  * protocol message.
441  */
442
443 static void
444 rfbProcessClientNormalMessage(cl)
445     rfbClientPtr cl;
446 {
447     int n;
448     rfbClientToServerMsg msg;
449     char *str;
450
451     if ((n = ReadExact(cl->sock, (char *)&msg, 1)) <= 0) {
452         if (n != 0)
453             rfbLogPerror("rfbProcessClientNormalMessage: read");
454         rfbCloseSock(cl->sock);
455         return;
456     }
457
458     switch (msg.type) {
459
460     case rfbSetPixelFormat:
461
462         if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
463                            sz_rfbSetPixelFormatMsg - 1)) <= 0) {
464             if (n != 0)
465                 rfbLogPerror("rfbProcessClientNormalMessage: read");
466             rfbCloseSock(cl->sock);
467             return;
468         }
469
470         cl->format.bitsPerPixel = msg.spf.format.bitsPerPixel;
471         cl->format.depth = msg.spf.format.depth;
472         cl->format.bigEndian = (msg.spf.format.bigEndian ? 1 : 0);
473         cl->format.trueColour = (msg.spf.format.trueColour ? 1 : 0);
474         cl->format.redMax = Swap16IfLE(msg.spf.format.redMax);
475         cl->format.greenMax = Swap16IfLE(msg.spf.format.greenMax);
476         cl->format.blueMax = Swap16IfLE(msg.spf.format.blueMax);
477         cl->format.redShift = msg.spf.format.redShift;
478         cl->format.greenShift = msg.spf.format.greenShift;
479         cl->format.blueShift = msg.spf.format.blueShift;
480
481         cl->readyForSetColourMapEntries = TRUE;
482
483         rfbSetTranslateFunction(cl);
484         return;
485
486
487     case rfbFixColourMapEntries:
488         if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
489                            sz_rfbFixColourMapEntriesMsg - 1)) <= 0) {
490             if (n != 0)
491                 rfbLogPerror("rfbProcessClientNormalMessage: read");
492             rfbCloseSock(cl->sock);
493             return;
494         }
495         rfbLog("rfbProcessClientNormalMessage: %s",
496                 "FixColourMapEntries unsupported\n");
497         rfbCloseSock(cl->sock);
498         return;
499
500
501     case rfbSetEncodings:
502     {
503         int i;
504         CARD32 enc;
505
506         if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
507                            sz_rfbSetEncodingsMsg - 1)) <= 0) {
508             if (n != 0)
509                 rfbLogPerror("rfbProcessClientNormalMessage: read");
510             rfbCloseSock(cl->sock);
511             return;
512         }
513
514         msg.se.nEncodings = Swap16IfLE(msg.se.nEncodings);
515
516         cl->preferredEncoding = -1;
517         cl->useCopyRect = FALSE;
518
519         for (i = 0; i < msg.se.nEncodings; i++) {
520             if ((n = ReadExact(cl->sock, (char *)&enc, 4)) <= 0) {
521                 if (n != 0)
522                     rfbLogPerror("rfbProcessClientNormalMessage: read");
523                 rfbCloseSock(cl->sock);
524                 return;
525             }
526             enc = Swap32IfLE(enc);
527
528             switch (enc) {
529
530             case rfbEncodingCopyRect:
531                 cl->useCopyRect = TRUE;
532                 break;
533             case rfbEncodingRaw:
534                 if (cl->preferredEncoding == -1) {
535                     cl->preferredEncoding = enc;
536                     rfbLog("Using raw encoding for client %s\n",
537                            cl->host);
538                 }
539                 break;
540             case rfbEncodingRRE:
541                 if (cl->preferredEncoding == -1) {
542                     cl->preferredEncoding = enc;
543                     rfbLog("Using rre encoding for client %s\n",
544                            cl->host);
545                 }
546                 break;
547             case rfbEncodingCoRRE:
548                 if (cl->preferredEncoding == -1) {
549                     cl->preferredEncoding = enc;
550                     rfbLog("Using CoRRE encoding for client %s\n",
551                            cl->host);
552                 }
553                 break;
554             case rfbEncodingHextile:
555                 if (cl->preferredEncoding == -1) {
556                     cl->preferredEncoding = enc;
557                     rfbLog("Using hextile encoding for client %s\n",
558                            cl->host);
559                 }
560                 break;
561             case rfbEncodingZRLE:
562                 if (cl->preferredEncoding == -1) {
563                     cl->preferredEncoding = enc;
564                     rfbLog("Using ZRLE encoding for client %s\n",
565                            cl->host);
566                 }
567                 break;
568             default:
569                 rfbLog("rfbProcessClientNormalMessage: ignoring unknown "
570                        "encoding type %d\n", (int)enc);
571             }
572         }
573
574         if (cl->preferredEncoding == -1) {
575             cl->preferredEncoding = rfbEncodingRaw;
576         }
577
578         return;
579     }
580
581
582     case rfbFramebufferUpdateRequest:
583     {
584         RegionRec tmpRegion;
585         BoxRec box;
586
587 #ifdef CORBA
588         addCapability(cl, DISPLAY_DEVICE);
589 #endif
590
591         if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
592                            sz_rfbFramebufferUpdateRequestMsg-1)) <= 0) {
593             if (n != 0)
594                 rfbLogPerror("rfbProcessClientNormalMessage: read");
595             rfbCloseSock(cl->sock);
596             return;
597         }
598
599         box.x1 = Swap16IfLE(msg.fur.x);
600         box.y1 = Swap16IfLE(msg.fur.y);
601         box.x2 = box.x1 + Swap16IfLE(msg.fur.w);
602         box.y2 = box.y1 + Swap16IfLE(msg.fur.h);
603         SAFE_REGION_INIT(pScreen,&tmpRegion,&box,0);
604
605         REGION_UNION(pScreen, &cl->requestedRegion, &cl->requestedRegion,
606                      &tmpRegion);
607
608         if (!cl->readyForSetColourMapEntries) {
609             /* client hasn't sent a SetPixelFormat so is using server's */
610             cl->readyForSetColourMapEntries = TRUE;
611             if (!cl->format.trueColour) {
612                 if (!rfbSetClientColourMap(cl, 0, 0)) {
613                     REGION_UNINIT(pScreen,&tmpRegion);
614                     return;
615                 }
616             }
617         }
618
619         if (!msg.fur.incremental) {
620             REGION_UNION(pScreen,&cl->modifiedRegion,&cl->modifiedRegion,
621                          &tmpRegion);
622             REGION_SUBTRACT(pScreen,&cl->copyRegion,&cl->copyRegion,
623                             &tmpRegion);
624         }
625
626         if (FB_UPDATE_PENDING(cl)) {
627           if (!cl->deferredUpdateScheduled)
628             rfbScheduleDeferredUpdate(cl);
629         }
630
631         REGION_UNINIT(pScreen,&tmpRegion);
632         return;
633     }
634
635     case rfbKeyEvent:
636
637         cl->rfbKeyEventsRcvd++;
638
639         if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
640                            sz_rfbKeyEventMsg - 1)) <= 0) {
641             if (n != 0)
642                 rfbLogPerror("rfbProcessClientNormalMessage: read");
643             rfbCloseSock(cl->sock);
644             return;
645         }
646
647 #ifdef CORBA
648         addCapability(cl, KEYBOARD_DEVICE);
649
650         if (!isKeyboardEnabled(cl))
651             return;
652 #endif
653         KbdAddEvent(msg.ke.down, (KeySym)Swap32IfLE(msg.ke.key), cl);
654         return;
655
656
657     case rfbPointerEvent:
658
659         cl->rfbPointerEventsRcvd++;
660
661         if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
662                            sz_rfbPointerEventMsg - 1)) <= 0) {
663             if (n != 0)
664                 rfbLogPerror("rfbProcessClientNormalMessage: read");
665             rfbCloseSock(cl->sock);
666             return;
667         }
668
669 #ifdef CORBA
670         addCapability(cl, POINTER_DEVICE);
671
672         if (!isPointerEnabled(cl))
673             return;
674 #endif
675
676         if (pointerClient && (pointerClient != cl))
677             return;
678
679         if (msg.pe.buttonMask == 0)
680             pointerClient = NULL;
681         else
682             pointerClient = cl;
683
684         PtrAddEvent(msg.pe.buttonMask,
685                     Swap16IfLE(msg.pe.x), Swap16IfLE(msg.pe.y), cl);
686         return;
687
688
689     case rfbClientCutText:
690
691         if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
692                            sz_rfbClientCutTextMsg - 1)) <= 0) {
693             if (n != 0)
694                 rfbLogPerror("rfbProcessClientNormalMessage: read");
695             rfbCloseSock(cl->sock);
696             return;
697         }
698
699         msg.cct.length = Swap32IfLE(msg.cct.length);
700
701         str = (char *)xalloc(msg.cct.length);
702
703         if ((n = ReadExact(cl->sock, str, msg.cct.length)) <= 0) {
704             if (n != 0)
705                 rfbLogPerror("rfbProcessClientNormalMessage: read");
706             xfree(str);
707             rfbCloseSock(cl->sock);
708             return;
709         }
710
711         rfbSetXCutText(str, msg.cct.length);
712
713         xfree(str);
714         return;
715
716
717     default:
718
719         rfbLog("rfbProcessClientNormalMessage: unknown message type %d\n",
720                 msg.type);
721         rfbLog(" ... closing connection\n");
722         rfbCloseSock(cl->sock);
723         return;
724     }
725 }
726
727
728
729 /*
730  * rfbSendFramebufferUpdate - send the currently pending framebuffer update to
731  * the RFB client.
732  */
733
734 Bool
735 rfbSendFramebufferUpdate(cl)
736     rfbClientPtr cl;
737 {
738     ScreenPtr pScreen = screenInfo.screens[0];
739     int i;
740     int nUpdateRegionRects;
741     rfbFramebufferUpdateMsg *fu = (rfbFramebufferUpdateMsg *)updateBuf;
742     RegionRec updateRegion, updateCopyRegion;
743     int dx, dy;
744     int bytesSent, rectsSent;
745
746     /*
747      * If the cursor isn't drawn, make sure it's put up.
748      */
749
750     if (!rfbScreen.cursorIsDrawn) {
751         rfbSpriteRestoreCursor(pScreen);
752     }
753
754     /*
755      * The modifiedRegion may overlap the destination copyRegion.  We remove
756      * any overlapping bits from the copyRegion (since they'd only be
757      * overwritten anyway).
758      */
759
760     REGION_SUBTRACT(pScreen, &cl->copyRegion, &cl->copyRegion,
761                     &cl->modifiedRegion);
762
763     /*
764      * The client is interested in the region requestedRegion.  The region
765      * which should be updated now is the intersection of requestedRegion
766      * and the union of modifiedRegion and copyRegion.  If it's empty then
767      * no update is needed.
768      */
769
770     REGION_INIT(pScreen,&updateRegion,NullBox,0);
771     REGION_UNION(pScreen, &updateRegion, &cl->copyRegion,
772                  &cl->modifiedRegion);
773     REGION_INTERSECT(pScreen, &updateRegion, &cl->requestedRegion,
774                      &updateRegion);
775
776     if (!REGION_NOTEMPTY(pScreen,&updateRegion)) {
777         REGION_UNINIT(pScreen,&updateRegion);
778         return TRUE;
779     }
780
781     if (rfbTrace) {
782       rfbLog("Sending update...\n");
783       bytesSent = cl->rfbBytesSent[cl->preferredEncoding];
784       rectsSent = cl->rfbRectanglesSent[cl->preferredEncoding];
785     }
786
787     /*
788      * We assume that the client doesn't have any pixel data outside the
789      * requestedRegion.  In other words, both the source and destination of a
790      * copy must lie within requestedRegion.  So the region we can send as a
791      * copy is the intersection of the copyRegion with both the requestedRegion
792      * and the requestedRegion translated by the amount of the copy.  We set
793      * updateCopyRegion to this.
794      */
795
796     REGION_INIT(pScreen,&updateCopyRegion,NullBox,0);
797     REGION_INTERSECT(pScreen, &updateCopyRegion, &cl->copyRegion,
798                      &cl->requestedRegion);
799     REGION_TRANSLATE(pScreen, &cl->requestedRegion, cl->copyDX, cl->copyDY);
800     REGION_INTERSECT(pScreen, &updateCopyRegion, &updateCopyRegion,
801                      &cl->requestedRegion);
802     dx = cl->copyDX;
803     dy = cl->copyDY;
804
805     /*
806      * Next we remove updateCopyRegion from updateRegion so that updateRegion
807      * is the part of this update which is sent as ordinary pixel data (i.e not
808      * a copy).
809      */
810
811     REGION_SUBTRACT(pScreen, &updateRegion, &updateRegion, &updateCopyRegion);
812
813     /*
814      * Finally we leave modifiedRegion to be the remainder (if any) of parts of
815      * the screen which are modified but outside the requestedRegion.  We also
816      * empty both the requestedRegion and the copyRegion - note that we never
817      * carry over a copyRegion for a future update.
818      */
819
820     REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
821                  &cl->copyRegion);
822     REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
823                     &updateRegion);
824     REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
825                     &updateCopyRegion);
826
827     REGION_EMPTY(pScreen, &cl->requestedRegion);
828     REGION_EMPTY(pScreen, &cl->copyRegion);
829     cl->copyDX = 0;
830     cl->copyDY = 0;
831
832     /*
833      * Now send the update.
834      */
835
836     cl->rfbFramebufferUpdateMessagesSent++;
837
838     if (cl->preferredEncoding == rfbEncodingCoRRE) {
839         nUpdateRegionRects = 0;
840
841         for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) {
842             int x = REGION_RECTS(&updateRegion)[i].x1;
843             int y = REGION_RECTS(&updateRegion)[i].y1;
844             int w = REGION_RECTS(&updateRegion)[i].x2 - x;
845             int h = REGION_RECTS(&updateRegion)[i].y2 - y;
846             nUpdateRegionRects += (((w-1) / cl->correMaxWidth + 1)
847                                      * ((h-1) / cl->correMaxHeight + 1));
848         }
849     } else {
850         nUpdateRegionRects = REGION_NUM_RECTS(&updateRegion);
851     }
852
853     if (nUpdateRegionRects > rfbMaxRects) {
854       BoxRec boundingBox = *(REGION_EXTENTS(pScreen, &updateRegion));
855       REGION_RESET(pScreen, &updateRegion, &boundingBox);
856       nUpdateRegionRects = 1;
857     }
858
859     fu->type = rfbFramebufferUpdate;
860     fu->nRects = Swap16IfLE(REGION_NUM_RECTS(&updateCopyRegion)
861                             + nUpdateRegionRects);
862     ublen = sz_rfbFramebufferUpdateMsg;
863
864     if (REGION_NOTEMPTY(pScreen,&updateCopyRegion)) {
865         if (!rfbSendCopyRegion(cl,&updateCopyRegion,dx,dy)) {
866             REGION_UNINIT(pScreen,&updateRegion);
867             REGION_UNINIT(pScreen,&updateCopyRegion);
868             return FALSE;
869         }
870     }
871
872     REGION_UNINIT(pScreen,&updateCopyRegion);
873
874     for (i = 0; i < REGION_NUM_RECTS(&updateRegion); i++) {
875         int x = REGION_RECTS(&updateRegion)[i].x1;
876         int y = REGION_RECTS(&updateRegion)[i].y1;
877         int w = REGION_RECTS(&updateRegion)[i].x2 - x;
878         int h = REGION_RECTS(&updateRegion)[i].y2 - y;
879
880         cl->rfbRawBytesEquivalent += (sz_rfbFramebufferUpdateRectHeader
881                                       + w * (cl->format.bitsPerPixel / 8) * h);
882
883         switch (cl->preferredEncoding) {
884         case rfbEncodingRaw:
885             if (!rfbSendRectEncodingRaw(cl, x, y, w, h)) {
886                 REGION_UNINIT(pScreen,&updateRegion);
887                 return FALSE;
888             }
889             break;
890         case rfbEncodingRRE:
891             if (!rfbSendRectEncodingRRE(cl, x, y, w, h)) {
892                 REGION_UNINIT(pScreen,&updateRegion);
893                 return FALSE;
894             }
895             break;
896         case rfbEncodingCoRRE:
897             if (!rfbSendRectEncodingCoRRE(cl, x, y, w, h)) {
898                 REGION_UNINIT(pScreen,&updateRegion);
899                 return FALSE;
900             }
901             break;
902         case rfbEncodingHextile:
903             if (!rfbSendRectEncodingHextile(cl, x, y, w, h)) {
904                 REGION_UNINIT(pScreen,&updateRegion);
905                 return FALSE;
906             }
907             break;
908         case rfbEncodingZRLE:
909             if (!rfbSendRectEncodingZRLE(cl, x, y, w, h)) {
910                 REGION_UNINIT(pScreen,&updateRegion);
911                 return FALSE;
912             }
913             break;
914         }
915     }
916
917     REGION_UNINIT(pScreen,&updateRegion);
918
919     if (!rfbSendUpdateBuf(cl))
920         return FALSE;
921
922     if (rfbTrace) {
923       bytesSent = cl->rfbBytesSent[cl->preferredEncoding] - bytesSent;
924       rectsSent = cl->rfbRectanglesSent[cl->preferredEncoding] - rectsSent;
925       rfbLog("...sent %d bytes, %d rects\n",bytesSent,rectsSent);
926     }
927
928     return TRUE;
929 }
930
931
932
933 /*
934  * Send the copy region as a string of CopyRect encoded rectangles.
935  * The only slightly tricky thing is that we should send the messages in
936  * the correct order so that an earlier CopyRect will not corrupt the source
937  * of a later one.
938  */
939
940 static Bool
941 rfbSendCopyRegion(cl, reg, dx, dy)
942     rfbClientPtr cl;
943     RegionPtr reg;
944     int dx, dy;
945 {
946     int nrects, nrectsInBand, x_inc, y_inc, thisRect, firstInNextBand;
947     int x, y, w, h;
948     rfbFramebufferUpdateRectHeader rect;
949     rfbCopyRect cr;
950
951     nrects = REGION_NUM_RECTS(reg);
952
953     if (dx <= 0) {
954         x_inc = 1;
955     } else {
956         x_inc = -1;
957     }
958
959     if (dy <= 0) {
960         thisRect = 0;
961         y_inc = 1;
962     } else {
963         thisRect = nrects - 1;
964         y_inc = -1;
965     }
966
967     while (nrects > 0) {
968
969         firstInNextBand = thisRect;
970         nrectsInBand = 0;
971
972         while ((nrects > 0) &&
973                (REGION_RECTS(reg)[firstInNextBand].y1
974                 == REGION_RECTS(reg)[thisRect].y1))
975         {
976             firstInNextBand += y_inc;
977             nrects--;
978             nrectsInBand++;
979         }
980
981         if (x_inc != y_inc) {
982             thisRect = firstInNextBand - y_inc;
983         }
984
985         while (nrectsInBand > 0) {
986             if ((ublen + sz_rfbFramebufferUpdateRectHeader
987                  + sz_rfbCopyRect) > UPDATE_BUF_SIZE)
988             {
989                 if (!rfbSendUpdateBuf(cl))
990                     return FALSE;
991             }
992
993             x = REGION_RECTS(reg)[thisRect].x1;
994             y = REGION_RECTS(reg)[thisRect].y1;
995             w = REGION_RECTS(reg)[thisRect].x2 - x;
996             h = REGION_RECTS(reg)[thisRect].y2 - y;
997
998             rect.r.x = Swap16IfLE(x);
999             rect.r.y = Swap16IfLE(y);
1000             rect.r.w = Swap16IfLE(w);
1001             rect.r.h = Swap16IfLE(h);
1002             rect.encoding = Swap32IfLE(rfbEncodingCopyRect);
1003
1004             memcpy(&updateBuf[ublen], (char *)&rect,
1005                    sz_rfbFramebufferUpdateRectHeader);
1006             ublen += sz_rfbFramebufferUpdateRectHeader;
1007
1008             cr.srcX = Swap16IfLE(x - dx);
1009             cr.srcY = Swap16IfLE(y - dy);
1010
1011             memcpy(&updateBuf[ublen], (char *)&cr, sz_rfbCopyRect);
1012             ublen += sz_rfbCopyRect;
1013
1014             cl->rfbRectanglesSent[rfbEncodingCopyRect]++;
1015             cl->rfbBytesSent[rfbEncodingCopyRect]
1016                 += sz_rfbFramebufferUpdateRectHeader + sz_rfbCopyRect;
1017
1018             thisRect += x_inc;
1019             nrectsInBand--;
1020         }
1021
1022         thisRect = firstInNextBand;
1023     }
1024
1025     return TRUE;
1026 }
1027
1028
1029 /*
1030  * Send a given rectangle in raw encoding (rfbEncodingRaw).
1031  */
1032
1033 Bool
1034 rfbSendRectEncodingRaw(cl, x, y, w, h)
1035     rfbClientPtr cl;
1036     int x, y, w, h;
1037 {
1038     rfbFramebufferUpdateRectHeader rect;
1039     int nlines;
1040     int bytesPerLine = w * (cl->format.bitsPerPixel / 8);
1041     char *fbptr = (rfbScreen.pfbMemory + (rfbScreen.paddedWidthInBytes * y)
1042                    + (x * (rfbScreen.bitsPerPixel / 8)));
1043
1044     if (ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
1045         if (!rfbSendUpdateBuf(cl))
1046             return FALSE;
1047     }
1048
1049     rect.r.x = Swap16IfLE(x);
1050     rect.r.y = Swap16IfLE(y);
1051     rect.r.w = Swap16IfLE(w);
1052     rect.r.h = Swap16IfLE(h);
1053     rect.encoding = Swap32IfLE(rfbEncodingRaw);
1054
1055     memcpy(&updateBuf[ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
1056     ublen += sz_rfbFramebufferUpdateRectHeader;
1057
1058     cl->rfbRectanglesSent[rfbEncodingRaw]++;
1059     cl->rfbBytesSent[rfbEncodingRaw]
1060         += sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h;
1061
1062     nlines = (UPDATE_BUF_SIZE - ublen) / bytesPerLine;
1063
1064     while (TRUE) {
1065         if (nlines > h)
1066             nlines = h;
1067
1068         (*cl->translateFn)(cl->translateLookupTable, &rfbServerFormat,
1069                            &cl->format, fbptr, &updateBuf[ublen],
1070                            rfbScreen.paddedWidthInBytes, w, nlines);
1071
1072         ublen += nlines * bytesPerLine;
1073         h -= nlines;
1074
1075         if (h == 0)     /* rect fitted in buffer, do next one */
1076             return TRUE;
1077
1078         /* buffer full - flush partial rect and do another nlines */
1079
1080         if (!rfbSendUpdateBuf(cl))
1081             return FALSE;
1082
1083         fbptr += (rfbScreen.paddedWidthInBytes * nlines);
1084
1085         nlines = (UPDATE_BUF_SIZE - ublen) / bytesPerLine;
1086         if (nlines == 0) {
1087             rfbLog("rfbSendRectEncodingRaw: send buffer too small for %d "
1088                    "bytes per line\n", bytesPerLine);
1089             rfbCloseSock(cl->sock);
1090             return FALSE;
1091         }
1092     }
1093 }
1094
1095
1096
1097 /*
1098  * Send the contents of updateBuf.  Returns 1 if successful, -1 if
1099  * not (errno should be set).
1100  */
1101
1102 Bool
1103 rfbSendUpdateBuf(cl)
1104     rfbClientPtr cl;
1105 {
1106     /*
1107     int i;
1108     for (i = 0; i < ublen; i++) {
1109         fprintf(stderr,"%02x ",((unsigned char *)updateBuf)[i]);
1110     }
1111     fprintf(stderr,"\n");
1112     */
1113
1114     if (WriteExact(cl->sock, updateBuf, ublen) < 0) {
1115         rfbLogPerror("rfbSendUpdateBuf: write");
1116         rfbCloseSock(cl->sock);
1117         return FALSE;
1118     }
1119
1120     ublen = 0;
1121     return TRUE;
1122 }
1123
1124
1125
1126 /*
1127  * rfbSendSetColourMapEntries sends a SetColourMapEntries message to the
1128  * client, using values from the currently installed colormap.
1129  */
1130
1131 Bool
1132 rfbSendSetColourMapEntries(cl, firstColour, nColours)
1133     rfbClientPtr cl;
1134     int firstColour;
1135     int nColours;
1136 {
1137     char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2];
1138     rfbSetColourMapEntriesMsg *scme = (rfbSetColourMapEntriesMsg *)buf;
1139     CARD16 *rgb = (CARD16 *)(&buf[sz_rfbSetColourMapEntriesMsg]);
1140     EntryPtr pent;
1141     int i, len;
1142
1143     scme->type = rfbSetColourMapEntries;
1144
1145     scme->firstColour = Swap16IfLE(firstColour);
1146     scme->nColours = Swap16IfLE(nColours);
1147
1148     len = sz_rfbSetColourMapEntriesMsg;
1149
1150     pent = (EntryPtr)&rfbInstalledColormap->red[firstColour];
1151     for (i = 0; i < nColours; i++) {
1152         if (pent->fShared) {
1153             rgb[i*3] = Swap16IfLE(pent->co.shco.red->color);
1154             rgb[i*3+1] = Swap16IfLE(pent->co.shco.green->color);
1155             rgb[i*3+2] = Swap16IfLE(pent->co.shco.blue->color);
1156         } else {
1157             rgb[i*3] = Swap16IfLE(pent->co.local.red);
1158             rgb[i*3+1] = Swap16IfLE(pent->co.local.green);
1159             rgb[i*3+2] = Swap16IfLE(pent->co.local.blue);
1160         }
1161         pent++;
1162     }
1163
1164     len += nColours * 3 * 2;
1165
1166     if (WriteExact(cl->sock, buf, len) < 0) {
1167         rfbLogPerror("rfbSendSetColourMapEntries: write");
1168         rfbCloseSock(cl->sock);
1169         return FALSE;
1170     }
1171     return TRUE;
1172 }
1173
1174
1175 /*
1176  * rfbSendBell sends a Bell message to all the clients.
1177  */
1178
1179 void
1180 rfbSendBell()
1181 {
1182     rfbClientPtr cl, nextCl;
1183     rfbBellMsg b;
1184
1185     for (cl = rfbClientHead; cl; cl = nextCl) {
1186         nextCl = cl->next;
1187         b.type = rfbBell;
1188         if (WriteExact(cl->sock, (char *)&b, sz_rfbBellMsg) < 0) {
1189             rfbLogPerror("rfbSendBell: write");
1190             rfbCloseSock(cl->sock);
1191         }
1192     }
1193 }
1194
1195
1196 /*
1197  * rfbSendServerCutText sends a ServerCutText message to all the clients.
1198  */
1199
1200 void
1201 rfbSendServerCutText(char *str, int len)
1202 {
1203     rfbClientPtr cl, nextCl;
1204     rfbServerCutTextMsg sct;
1205
1206     for (cl = rfbClientHead; cl; cl = nextCl) {
1207         nextCl = cl->next;
1208         sct.type = rfbServerCutText;
1209         sct.length = Swap32IfLE(len);
1210         if (WriteExact(cl->sock, (char *)&sct,
1211                        sz_rfbServerCutTextMsg) < 0) {
1212             rfbLogPerror("rfbSendServerCutText: write");
1213             rfbCloseSock(cl->sock);
1214             continue;
1215         }
1216         if (WriteExact(cl->sock, str, len) < 0) {
1217             rfbLogPerror("rfbSendServerCutText: write");
1218             rfbCloseSock(cl->sock);
1219         }
1220     }
1221 }