2 * rfbserver.c - deal with server-side of the RFB protocol.
6 * Copyright (C) 2002-2003 RealVNC Ltd.
7 * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
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.
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.
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,
25 /* Use ``#define CORBA'' to enable CORBA control interface */
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35 #include "windowstr.h"
38 #include "mipointer.h"
42 #include <vncserverctrl.h>
45 char updateBuf[UPDATE_BUF_SIZE];
48 rfbClientPtr rfbClientHead = NULL;
49 rfbClientPtr pointerClient = NULL; /* Mutex for pointer events */
51 Bool rfbAlwaysShared = FALSE;
52 Bool rfbNeverShared = FALSE;
53 Bool rfbDontDisconnect = FALSE;
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);
64 * rfbNewClientConnection is called from sockets.c when a new connection
69 rfbNewClientConnection(sock)
74 cl = rfbNewClient(sock);
78 newConnection(cl, (KEYBOARD_DEVICE|POINTER_DEVICE), 1, 1, 1);
84 * rfbReverseConnection is called by the CORBA stuff to make an outward
85 * connection to a "listening" RFB client.
89 rfbReverseConnection(host, port)
96 if ((sock = rfbConnect(host, port)) < 0)
97 return (rfbClientPtr)NULL;
99 cl = rfbNewClient(sock);
102 cl->reverseConnection = TRUE;
110 * rfbNewClient is called when a new connection has been made by whatever
118 rfbProtocolVersionMsg pv;
121 struct sockaddr_in addr;
122 unsigned int addrlen = sizeof(struct sockaddr_in);
124 if (rfbClientHead == NULL) {
125 /* no other clients - make sure we don't think any keys are pressed */
128 rfbLog(" (other clients");
129 for (cl = rfbClientHead; cl; cl = cl->next) {
130 fprintf(stderr," %s",cl->host);
132 fprintf(stderr,")\n");
135 cl = (rfbClientPtr)xalloc(sizeof(rfbClientRec));
138 getpeername(sock, (struct sockaddr *)&addr, &addrlen);
139 cl->host = strdup(inet_ntoa(addr.sin_addr));
141 cl->state = RFB_PROTOCOL_VERSION;
143 cl->reverseConnection = FALSE;
144 cl->readyForSetColourMapEntries = FALSE;
145 cl->useCopyRect = FALSE;
146 cl->preferredEncoding = rfbEncodingRaw;
147 cl->correMaxWidth = 48;
148 cl->correMaxHeight = 48;
151 REGION_INIT(pScreen,&cl->copyRegion,NullBox,0);
156 box.x2 = rfbScreen.width;
157 box.y2 = rfbScreen.height;
158 REGION_INIT(pScreen,&cl->modifiedRegion,&box,0);
160 REGION_INIT(pScreen,&cl->requestedRegion,NullBox,0);
162 cl->deferredUpdateScheduled = FALSE;
163 cl->deferredUpdateTimer = NULL;
165 cl->format = rfbServerFormat;
166 cl->translateFn = rfbTranslateNone;
167 cl->translateLookupTable = NULL;
169 cl->next = rfbClientHead;
174 sprintf(pv,rfbProtocolVersionFormat,rfbProtocolMajorVersion,
175 rfbProtocolMinorVersion);
177 if (WriteExact(sock, pv, sz_rfbProtocolVersionMsg) < 0) {
178 rfbLogPerror("rfbNewClient: write");
188 * rfbClientConnectionGone is called from sockets.c just after a connection
193 rfbClientConnectionGone(sock)
196 rfbClientPtr cl, prev;
198 for (prev = NULL, cl = rfbClientHead; cl; prev = cl, cl = cl->next) {
199 if (sock == cl->sock)
204 rfbLog("rfbClientConnectionGone: unknown socket %d\n",sock);
208 rfbLog("Client %s gone\n",cl->host);
211 if (pointerClient == cl)
212 pointerClient = NULL;
215 destroyConnection(cl);
219 prev->next = cl->next;
221 rfbClientHead = cl->next;
224 REGION_UNINIT(pScreen,&cl->copyRegion);
225 REGION_UNINIT(pScreen,&cl->modifiedRegion);
226 TimerFree(cl->deferredUpdateTimer);
230 if (cl->translateLookupTable) free(cl->translateLookupTable);
237 * rfbProcessClientMessage is called when there is data to read from a client.
241 rfbProcessClientMessage(sock)
246 for (cl = rfbClientHead; cl; cl = cl->next) {
247 if (sock == cl->sock)
252 rfbLog("rfbProcessClientMessage: unknown socket %d\n",sock);
258 if (isClosePending(cl)) {
259 rfbLog("Closing connection to client %s\n", cl->host);
266 case RFB_PROTOCOL_VERSION:
267 rfbProcessClientProtocolVersion(cl);
269 case RFB_AUTHENTICATION:
270 rfbAuthProcessClientMessage(cl);
272 case RFB_INITIALISATION:
273 rfbProcessClientInitMessage(cl);
276 rfbProcessClientNormalMessage(cl);
283 * rfbProcessClientProtocolVersion is called when the client sends its
288 rfbProcessClientProtocolVersion(cl)
291 rfbProtocolVersionMsg pv;
293 char failureReason[256];
295 if ((n = ReadExact(cl->sock, pv, sz_rfbProtocolVersionMsg)) <= 0) {
297 rfbLog("rfbProcessClientProtocolVersion: client gone\n");
299 rfbLogPerror("rfbProcessClientProtocolVersion: read");
300 rfbCloseSock(cl->sock);
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);
310 rfbLog("Protocol version %d.%d\n", major, minor);
312 if (major != rfbProtocolMajorVersion) {
313 /* Major version mismatch - send a ConnFailed message */
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);
323 if (minor != rfbProtocolMinorVersion) {
324 /* Minor version mismatch - warn but try to continue */
325 rfbLog("Ignoring minor version mismatch\n");
328 rfbAuthNewClient(cl);
333 * rfbClientConnFailed is called when a client connection has failed either
334 * because it talks the wrong protocol or it has failed authentication.
338 rfbClientConnFailed(cl, reason)
343 int len = strlen(reason);
345 buf = (char *)xalloc(8 + len);
346 ((CARD32 *)buf)[0] = Swap32IfLE(rfbConnFailed);
347 ((CARD32 *)buf)[1] = Swap32IfLE(len);
348 memcpy(buf + 8, reason, len);
350 if (WriteExact(cl->sock, buf, 8 + len) < 0)
351 rfbLogPerror("rfbClientConnFailed: write");
353 rfbCloseSock(cl->sock);
358 * rfbProcessClientInitMessage is called when the client sends its
359 * initialisation message.
363 rfbProcessClientInitMessage(cl)
368 rfbServerInitMsg *si = (rfbServerInitMsg *)buf;
371 rfbClientPtr otherCl, nextCl;
373 if ((n = ReadExact(cl->sock, (char *)&ci,sz_rfbClientInitMsg)) <= 0) {
375 rfbLog("rfbProcessClientInitMessage: client gone\n");
377 rfbLogPerror("rfbProcessClientInitMessage: read");
378 rfbCloseSock(cl->sock);
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);
389 user = getpwuid(getuid());
391 if (strlen(desktopName) > 128) /* sanity check on desktop name len */
392 desktopName[128] = 0;
395 sprintf(buf + sz_rfbServerInitMsg, "%s's %s desktop (%s:%s)",
396 user->pw_name, desktopName, rfbThisHost, display);
398 sprintf(buf + sz_rfbServerInitMsg, "%s desktop (%s:%s)",
399 desktopName, rfbThisHost, display);
401 len = strlen(buf + sz_rfbServerInitMsg);
402 si->nameLength = Swap32IfLE(len);
404 if (WriteExact(cl->sock, buf, sz_rfbServerInitMsg + len) < 0) {
405 rfbLogPerror("rfbProcessClientInitMessage: write");
406 rfbCloseSock(cl->sock);
410 cl->state = RFB_NORMAL;
412 if (!cl->reverseConnection &&
413 (rfbNeverShared || (!rfbAlwaysShared && !ci.shared))) {
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);
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",
430 rfbCloseSock(otherCl->sock);
439 * rfbProcessClientNormalMessage is called when the client has sent a normal
444 rfbProcessClientNormalMessage(cl)
448 rfbClientToServerMsg msg;
451 if ((n = ReadExact(cl->sock, (char *)&msg, 1)) <= 0) {
453 rfbLogPerror("rfbProcessClientNormalMessage: read");
454 rfbCloseSock(cl->sock);
460 case rfbSetPixelFormat:
462 if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
463 sz_rfbSetPixelFormatMsg - 1)) <= 0) {
465 rfbLogPerror("rfbProcessClientNormalMessage: read");
466 rfbCloseSock(cl->sock);
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;
481 cl->readyForSetColourMapEntries = TRUE;
483 rfbSetTranslateFunction(cl);
487 case rfbFixColourMapEntries:
488 if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
489 sz_rfbFixColourMapEntriesMsg - 1)) <= 0) {
491 rfbLogPerror("rfbProcessClientNormalMessage: read");
492 rfbCloseSock(cl->sock);
495 rfbLog("rfbProcessClientNormalMessage: %s",
496 "FixColourMapEntries unsupported\n");
497 rfbCloseSock(cl->sock);
501 case rfbSetEncodings:
506 if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
507 sz_rfbSetEncodingsMsg - 1)) <= 0) {
509 rfbLogPerror("rfbProcessClientNormalMessage: read");
510 rfbCloseSock(cl->sock);
514 msg.se.nEncodings = Swap16IfLE(msg.se.nEncodings);
516 cl->preferredEncoding = -1;
517 cl->useCopyRect = FALSE;
519 for (i = 0; i < msg.se.nEncodings; i++) {
520 if ((n = ReadExact(cl->sock, (char *)&enc, 4)) <= 0) {
522 rfbLogPerror("rfbProcessClientNormalMessage: read");
523 rfbCloseSock(cl->sock);
526 enc = Swap32IfLE(enc);
530 case rfbEncodingCopyRect:
531 cl->useCopyRect = TRUE;
534 if (cl->preferredEncoding == -1) {
535 cl->preferredEncoding = enc;
536 rfbLog("Using raw encoding for client %s\n",
541 if (cl->preferredEncoding == -1) {
542 cl->preferredEncoding = enc;
543 rfbLog("Using rre encoding for client %s\n",
547 case rfbEncodingCoRRE:
548 if (cl->preferredEncoding == -1) {
549 cl->preferredEncoding = enc;
550 rfbLog("Using CoRRE encoding for client %s\n",
554 case rfbEncodingHextile:
555 if (cl->preferredEncoding == -1) {
556 cl->preferredEncoding = enc;
557 rfbLog("Using hextile encoding for client %s\n",
561 case rfbEncodingZRLE:
562 if (cl->preferredEncoding == -1) {
563 cl->preferredEncoding = enc;
564 rfbLog("Using ZRLE encoding for client %s\n",
569 rfbLog("rfbProcessClientNormalMessage: ignoring unknown "
570 "encoding type %d\n", (int)enc);
574 if (cl->preferredEncoding == -1) {
575 cl->preferredEncoding = rfbEncodingRaw;
582 case rfbFramebufferUpdateRequest:
588 addCapability(cl, DISPLAY_DEVICE);
591 if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
592 sz_rfbFramebufferUpdateRequestMsg-1)) <= 0) {
594 rfbLogPerror("rfbProcessClientNormalMessage: read");
595 rfbCloseSock(cl->sock);
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);
605 REGION_UNION(pScreen, &cl->requestedRegion, &cl->requestedRegion,
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);
619 if (!msg.fur.incremental) {
620 REGION_UNION(pScreen,&cl->modifiedRegion,&cl->modifiedRegion,
622 REGION_SUBTRACT(pScreen,&cl->copyRegion,&cl->copyRegion,
626 if (FB_UPDATE_PENDING(cl)) {
627 if (!cl->deferredUpdateScheduled)
628 rfbScheduleDeferredUpdate(cl);
631 REGION_UNINIT(pScreen,&tmpRegion);
637 cl->rfbKeyEventsRcvd++;
639 if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
640 sz_rfbKeyEventMsg - 1)) <= 0) {
642 rfbLogPerror("rfbProcessClientNormalMessage: read");
643 rfbCloseSock(cl->sock);
648 addCapability(cl, KEYBOARD_DEVICE);
650 if (!isKeyboardEnabled(cl))
653 KbdAddEvent(msg.ke.down, (KeySym)Swap32IfLE(msg.ke.key), cl);
657 case rfbPointerEvent:
659 cl->rfbPointerEventsRcvd++;
661 if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
662 sz_rfbPointerEventMsg - 1)) <= 0) {
664 rfbLogPerror("rfbProcessClientNormalMessage: read");
665 rfbCloseSock(cl->sock);
670 addCapability(cl, POINTER_DEVICE);
672 if (!isPointerEnabled(cl))
676 if (pointerClient && (pointerClient != cl))
679 if (msg.pe.buttonMask == 0)
680 pointerClient = NULL;
684 PtrAddEvent(msg.pe.buttonMask,
685 Swap16IfLE(msg.pe.x), Swap16IfLE(msg.pe.y), cl);
689 case rfbClientCutText:
691 if ((n = ReadExact(cl->sock, ((char *)&msg) + 1,
692 sz_rfbClientCutTextMsg - 1)) <= 0) {
694 rfbLogPerror("rfbProcessClientNormalMessage: read");
695 rfbCloseSock(cl->sock);
699 msg.cct.length = Swap32IfLE(msg.cct.length);
701 str = (char *)xalloc(msg.cct.length);
703 if ((n = ReadExact(cl->sock, str, msg.cct.length)) <= 0) {
705 rfbLogPerror("rfbProcessClientNormalMessage: read");
707 rfbCloseSock(cl->sock);
711 rfbSetXCutText(str, msg.cct.length);
719 rfbLog("rfbProcessClientNormalMessage: unknown message type %d\n",
721 rfbLog(" ... closing connection\n");
722 rfbCloseSock(cl->sock);
730 * rfbSendFramebufferUpdate - send the currently pending framebuffer update to
735 rfbSendFramebufferUpdate(cl)
738 ScreenPtr pScreen = screenInfo.screens[0];
740 int nUpdateRegionRects;
741 rfbFramebufferUpdateMsg *fu = (rfbFramebufferUpdateMsg *)updateBuf;
742 RegionRec updateRegion, updateCopyRegion;
744 int bytesSent, rectsSent;
747 * If the cursor isn't drawn, make sure it's put up.
750 if (!rfbScreen.cursorIsDrawn) {
751 rfbSpriteRestoreCursor(pScreen);
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).
760 REGION_SUBTRACT(pScreen, &cl->copyRegion, &cl->copyRegion,
761 &cl->modifiedRegion);
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.
770 REGION_INIT(pScreen,&updateRegion,NullBox,0);
771 REGION_UNION(pScreen, &updateRegion, &cl->copyRegion,
772 &cl->modifiedRegion);
773 REGION_INTERSECT(pScreen, &updateRegion, &cl->requestedRegion,
776 if (!REGION_NOTEMPTY(pScreen,&updateRegion)) {
777 REGION_UNINIT(pScreen,&updateRegion);
782 rfbLog("Sending update...\n");
783 bytesSent = cl->rfbBytesSent[cl->preferredEncoding];
784 rectsSent = cl->rfbRectanglesSent[cl->preferredEncoding];
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.
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);
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
811 REGION_SUBTRACT(pScreen, &updateRegion, &updateRegion, &updateCopyRegion);
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.
820 REGION_UNION(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
822 REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
824 REGION_SUBTRACT(pScreen, &cl->modifiedRegion, &cl->modifiedRegion,
827 REGION_EMPTY(pScreen, &cl->requestedRegion);
828 REGION_EMPTY(pScreen, &cl->copyRegion);
833 * Now send the update.
836 cl->rfbFramebufferUpdateMessagesSent++;
838 if (cl->preferredEncoding == rfbEncodingCoRRE) {
839 nUpdateRegionRects = 0;
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));
850 nUpdateRegionRects = REGION_NUM_RECTS(&updateRegion);
853 if (nUpdateRegionRects > rfbMaxRects) {
854 BoxRec boundingBox = *(REGION_EXTENTS(pScreen, &updateRegion));
855 REGION_RESET(pScreen, &updateRegion, &boundingBox);
856 nUpdateRegionRects = 1;
859 fu->type = rfbFramebufferUpdate;
860 fu->nRects = Swap16IfLE(REGION_NUM_RECTS(&updateCopyRegion)
861 + nUpdateRegionRects);
862 ublen = sz_rfbFramebufferUpdateMsg;
864 if (REGION_NOTEMPTY(pScreen,&updateCopyRegion)) {
865 if (!rfbSendCopyRegion(cl,&updateCopyRegion,dx,dy)) {
866 REGION_UNINIT(pScreen,&updateRegion);
867 REGION_UNINIT(pScreen,&updateCopyRegion);
872 REGION_UNINIT(pScreen,&updateCopyRegion);
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;
880 cl->rfbRawBytesEquivalent += (sz_rfbFramebufferUpdateRectHeader
881 + w * (cl->format.bitsPerPixel / 8) * h);
883 switch (cl->preferredEncoding) {
885 if (!rfbSendRectEncodingRaw(cl, x, y, w, h)) {
886 REGION_UNINIT(pScreen,&updateRegion);
891 if (!rfbSendRectEncodingRRE(cl, x, y, w, h)) {
892 REGION_UNINIT(pScreen,&updateRegion);
896 case rfbEncodingCoRRE:
897 if (!rfbSendRectEncodingCoRRE(cl, x, y, w, h)) {
898 REGION_UNINIT(pScreen,&updateRegion);
902 case rfbEncodingHextile:
903 if (!rfbSendRectEncodingHextile(cl, x, y, w, h)) {
904 REGION_UNINIT(pScreen,&updateRegion);
908 case rfbEncodingZRLE:
909 if (!rfbSendRectEncodingZRLE(cl, x, y, w, h)) {
910 REGION_UNINIT(pScreen,&updateRegion);
917 REGION_UNINIT(pScreen,&updateRegion);
919 if (!rfbSendUpdateBuf(cl))
923 bytesSent = cl->rfbBytesSent[cl->preferredEncoding] - bytesSent;
924 rectsSent = cl->rfbRectanglesSent[cl->preferredEncoding] - rectsSent;
925 rfbLog("...sent %d bytes, %d rects\n",bytesSent,rectsSent);
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
941 rfbSendCopyRegion(cl, reg, dx, dy)
946 int nrects, nrectsInBand, x_inc, y_inc, thisRect, firstInNextBand;
948 rfbFramebufferUpdateRectHeader rect;
951 nrects = REGION_NUM_RECTS(reg);
963 thisRect = nrects - 1;
969 firstInNextBand = thisRect;
972 while ((nrects > 0) &&
973 (REGION_RECTS(reg)[firstInNextBand].y1
974 == REGION_RECTS(reg)[thisRect].y1))
976 firstInNextBand += y_inc;
981 if (x_inc != y_inc) {
982 thisRect = firstInNextBand - y_inc;
985 while (nrectsInBand > 0) {
986 if ((ublen + sz_rfbFramebufferUpdateRectHeader
987 + sz_rfbCopyRect) > UPDATE_BUF_SIZE)
989 if (!rfbSendUpdateBuf(cl))
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;
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);
1004 memcpy(&updateBuf[ublen], (char *)&rect,
1005 sz_rfbFramebufferUpdateRectHeader);
1006 ublen += sz_rfbFramebufferUpdateRectHeader;
1008 cr.srcX = Swap16IfLE(x - dx);
1009 cr.srcY = Swap16IfLE(y - dy);
1011 memcpy(&updateBuf[ublen], (char *)&cr, sz_rfbCopyRect);
1012 ublen += sz_rfbCopyRect;
1014 cl->rfbRectanglesSent[rfbEncodingCopyRect]++;
1015 cl->rfbBytesSent[rfbEncodingCopyRect]
1016 += sz_rfbFramebufferUpdateRectHeader + sz_rfbCopyRect;
1022 thisRect = firstInNextBand;
1030 * Send a given rectangle in raw encoding (rfbEncodingRaw).
1034 rfbSendRectEncodingRaw(cl, x, y, w, h)
1038 rfbFramebufferUpdateRectHeader rect;
1040 int bytesPerLine = w * (cl->format.bitsPerPixel / 8);
1041 char *fbptr = (rfbScreen.pfbMemory + (rfbScreen.paddedWidthInBytes * y)
1042 + (x * (rfbScreen.bitsPerPixel / 8)));
1044 if (ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
1045 if (!rfbSendUpdateBuf(cl))
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);
1055 memcpy(&updateBuf[ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
1056 ublen += sz_rfbFramebufferUpdateRectHeader;
1058 cl->rfbRectanglesSent[rfbEncodingRaw]++;
1059 cl->rfbBytesSent[rfbEncodingRaw]
1060 += sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h;
1062 nlines = (UPDATE_BUF_SIZE - ublen) / bytesPerLine;
1068 (*cl->translateFn)(cl->translateLookupTable, &rfbServerFormat,
1069 &cl->format, fbptr, &updateBuf[ublen],
1070 rfbScreen.paddedWidthInBytes, w, nlines);
1072 ublen += nlines * bytesPerLine;
1075 if (h == 0) /* rect fitted in buffer, do next one */
1078 /* buffer full - flush partial rect and do another nlines */
1080 if (!rfbSendUpdateBuf(cl))
1083 fbptr += (rfbScreen.paddedWidthInBytes * nlines);
1085 nlines = (UPDATE_BUF_SIZE - ublen) / bytesPerLine;
1087 rfbLog("rfbSendRectEncodingRaw: send buffer too small for %d "
1088 "bytes per line\n", bytesPerLine);
1089 rfbCloseSock(cl->sock);
1098 * Send the contents of updateBuf. Returns 1 if successful, -1 if
1099 * not (errno should be set).
1103 rfbSendUpdateBuf(cl)
1108 for (i = 0; i < ublen; i++) {
1109 fprintf(stderr,"%02x ",((unsigned char *)updateBuf)[i]);
1111 fprintf(stderr,"\n");
1114 if (WriteExact(cl->sock, updateBuf, ublen) < 0) {
1115 rfbLogPerror("rfbSendUpdateBuf: write");
1116 rfbCloseSock(cl->sock);
1127 * rfbSendSetColourMapEntries sends a SetColourMapEntries message to the
1128 * client, using values from the currently installed colormap.
1132 rfbSendSetColourMapEntries(cl, firstColour, nColours)
1137 char buf[sz_rfbSetColourMapEntriesMsg + 256 * 3 * 2];
1138 rfbSetColourMapEntriesMsg *scme = (rfbSetColourMapEntriesMsg *)buf;
1139 CARD16 *rgb = (CARD16 *)(&buf[sz_rfbSetColourMapEntriesMsg]);
1143 scme->type = rfbSetColourMapEntries;
1145 scme->firstColour = Swap16IfLE(firstColour);
1146 scme->nColours = Swap16IfLE(nColours);
1148 len = sz_rfbSetColourMapEntriesMsg;
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);
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);
1164 len += nColours * 3 * 2;
1166 if (WriteExact(cl->sock, buf, len) < 0) {
1167 rfbLogPerror("rfbSendSetColourMapEntries: write");
1168 rfbCloseSock(cl->sock);
1176 * rfbSendBell sends a Bell message to all the clients.
1182 rfbClientPtr cl, nextCl;
1185 for (cl = rfbClientHead; cl; cl = nextCl) {
1188 if (WriteExact(cl->sock, (char *)&b, sz_rfbBellMsg) < 0) {
1189 rfbLogPerror("rfbSendBell: write");
1190 rfbCloseSock(cl->sock);
1197 * rfbSendServerCutText sends a ServerCutText message to all the clients.
1201 rfbSendServerCutText(char *str, int len)
1203 rfbClientPtr cl, nextCl;
1204 rfbServerCutTextMsg sct;
1206 for (cl = rfbClientHead; cl; cl = nextCl) {
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);
1216 if (WriteExact(cl->sock, str, len) < 0) {
1217 rfbLogPerror("rfbSendServerCutText: write");
1218 rfbCloseSock(cl->sock);