parent
a1ce2ac48f
commit
0fc57f2054
@ -0,0 +1,17 @@
|
|||||||
|
CFLAGS=-g -I.. -I. -Wall
|
||||||
|
LDLIBS=-lz -ljpeg
|
||||||
|
|
||||||
|
OBJS=cursor.o listen.o rfbproto.o sockets.o vncviewer.o ../libvncserver.a
|
||||||
|
|
||||||
|
all: libvncclient.a
|
||||||
|
|
||||||
|
rfbproto.o: rfbproto.c corre.c hextile.c rre.c tight.c zlib.c
|
||||||
|
|
||||||
|
$(OBJS): ../rfb/rfbclient.h
|
||||||
|
|
||||||
|
libvncclient.a: $(OBJS)
|
||||||
|
$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm *.o *.a
|
||||||
|
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this software; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* corre.c - handle CoRRE encoding.
|
||||||
|
*
|
||||||
|
* This file shouldn't be compiled directly. It is included multiple times by
|
||||||
|
* rfbproto.c, each time with a different definition of the macro BPP. For
|
||||||
|
* each value of BPP, this file defines a function which handles a CoRRE
|
||||||
|
* encoded rectangle with BPP bits per pixel.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define HandleCoRREBPP CONCAT2E(HandleCoRRE,BPP)
|
||||||
|
#define CARDBPP CONCAT3E(uint,BPP,_t)
|
||||||
|
|
||||||
|
static Bool
|
||||||
|
HandleCoRREBPP (rfbClient* client, int rx, int ry, int rw, int rh)
|
||||||
|
{
|
||||||
|
rfbRREHeader hdr;
|
||||||
|
int i;
|
||||||
|
CARDBPP pix;
|
||||||
|
uint8_t *ptr;
|
||||||
|
int x, y, w, h;
|
||||||
|
|
||||||
|
if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbRREHeader))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
hdr.nSubrects = Swap32IfLE(hdr.nSubrects);
|
||||||
|
|
||||||
|
if (!ReadFromRFBServer(client, (char *)&pix, sizeof(pix)))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
FillRectangle(client, rx, ry, rw, rh, pix);
|
||||||
|
|
||||||
|
if (!ReadFromRFBServer(client, client->buffer, hdr.nSubrects * (4 + (BPP / 8))))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
ptr = (uint8_t *)client->buffer;
|
||||||
|
|
||||||
|
for (i = 0; i < hdr.nSubrects; i++) {
|
||||||
|
pix = *(CARDBPP *)ptr;
|
||||||
|
ptr += BPP/8;
|
||||||
|
x = *ptr++;
|
||||||
|
y = *ptr++;
|
||||||
|
w = *ptr++;
|
||||||
|
h = *ptr++;
|
||||||
|
|
||||||
|
FillRectangle(client, rx+x, ry+y, w, h, pix);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef CARDBPP
|
@ -0,0 +1,175 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2001,2002 Constantin Kaplinsky. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this software; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* cursor.c - code to support cursor shape updates (XCursor and
|
||||||
|
* RichCursor preudo-encodings).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <rfb/rfbclient.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define OPER_SAVE 0
|
||||||
|
#define OPER_RESTORE 1
|
||||||
|
|
||||||
|
#define RGB24_TO_PIXEL(bpp,r,g,b) \
|
||||||
|
((((uint##bpp##_t)(r) & 0xFF) * client->format.redMax + 127) / 255 \
|
||||||
|
<< client->format.redShift | \
|
||||||
|
(((uint##bpp##_t)(g) & 0xFF) * client->format.greenMax + 127) / 255 \
|
||||||
|
<< client->format.greenShift | \
|
||||||
|
(((uint##bpp##_t)(b) & 0xFF) * client->format.blueMax + 127) / 255 \
|
||||||
|
<< client->format.blueShift)
|
||||||
|
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* HandleCursorShape(). Support for XCursor and RichCursor shape
|
||||||
|
* updates. We emulate cursor operating on the frame buffer (that is
|
||||||
|
* why we call it "software cursor").
|
||||||
|
********************************************************************/
|
||||||
|
|
||||||
|
Bool HandleCursorShape(rfbClient* client,int xhot, int yhot, int width, int height, uint32_t enc)
|
||||||
|
{
|
||||||
|
int bytesPerPixel;
|
||||||
|
size_t bytesPerRow, bytesMaskData;
|
||||||
|
rfbXCursorColors rgb;
|
||||||
|
uint32_t colors[2];
|
||||||
|
char *buf;
|
||||||
|
uint8_t *ptr;
|
||||||
|
int x, y, b;
|
||||||
|
|
||||||
|
bytesPerPixel = client->format.bitsPerPixel / 8;
|
||||||
|
bytesPerRow = (width + 7) / 8;
|
||||||
|
bytesMaskData = bytesPerRow * height;
|
||||||
|
|
||||||
|
if (width * height == 0)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/* Allocate memory for pixel data and temporary mask data. */
|
||||||
|
if(client->rcSource)
|
||||||
|
free(client->rcSource);
|
||||||
|
|
||||||
|
client->rcSource = malloc(width * height * bytesPerPixel);
|
||||||
|
if (client->rcSource == NULL)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
buf = malloc(bytesMaskData);
|
||||||
|
if (buf == NULL) {
|
||||||
|
free(client->rcSource);
|
||||||
|
client->rcSource = NULL;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read and decode cursor pixel data, depending on the encoding type. */
|
||||||
|
|
||||||
|
if (enc == rfbEncodingXCursor) {
|
||||||
|
/* Read and convert background and foreground colors. */
|
||||||
|
if (!ReadFromRFBServer(client, (char *)&rgb, sz_rfbXCursorColors)) {
|
||||||
|
free(client->rcSource);
|
||||||
|
client->rcSource = NULL;
|
||||||
|
free(buf);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
colors[0] = RGB24_TO_PIXEL(32, rgb.backRed, rgb.backGreen, rgb.backBlue);
|
||||||
|
colors[1] = RGB24_TO_PIXEL(32, rgb.foreRed, rgb.foreGreen, rgb.foreBlue);
|
||||||
|
|
||||||
|
/* Read 1bpp pixel data into a temporary buffer. */
|
||||||
|
if (!ReadFromRFBServer(client, buf, bytesMaskData)) {
|
||||||
|
free(client->rcSource);
|
||||||
|
client->rcSource = NULL;
|
||||||
|
free(buf);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert 1bpp data to byte-wide color indices. */
|
||||||
|
ptr = client->rcSource;
|
||||||
|
for (y = 0; y < height; y++) {
|
||||||
|
for (x = 0; x < width / 8; x++) {
|
||||||
|
for (b = 7; b >= 0; b--) {
|
||||||
|
*ptr = buf[y * bytesPerRow + x] >> b & 1;
|
||||||
|
ptr += bytesPerPixel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (b = 7; b > 7 - width % 8; b--) {
|
||||||
|
*ptr = buf[y * bytesPerRow + x] >> b & 1;
|
||||||
|
ptr += bytesPerPixel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert indices into the actual pixel values. */
|
||||||
|
switch (bytesPerPixel) {
|
||||||
|
case 1:
|
||||||
|
for (x = 0; x < width * height; x++)
|
||||||
|
client->rcSource[x] = (uint8_t)colors[client->rcSource[x]];
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
for (x = 0; x < width * height; x++)
|
||||||
|
((uint16_t *)client->rcSource)[x] = (uint16_t)colors[client->rcSource[x * 2]];
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
for (x = 0; x < width * height; x++)
|
||||||
|
((uint32_t *)client->rcSource)[x] = colors[client->rcSource[x * 4]];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else { /* enc == rfbEncodingRichCursor */
|
||||||
|
|
||||||
|
if (!ReadFromRFBServer(client, (char *)client->rcSource, width * height * bytesPerPixel)) {
|
||||||
|
free(client->rcSource);
|
||||||
|
client->rcSource = NULL;
|
||||||
|
free(buf);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read and decode mask data. */
|
||||||
|
|
||||||
|
if (!ReadFromRFBServer(client, buf, bytesMaskData)) {
|
||||||
|
free(client->rcSource);
|
||||||
|
client->rcSource = NULL;
|
||||||
|
free(buf);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
client->rcMask = malloc(width * height);
|
||||||
|
if (client->rcMask == NULL) {
|
||||||
|
free(client->rcSource);
|
||||||
|
client->rcSource = NULL;
|
||||||
|
free(buf);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr = client->rcMask;
|
||||||
|
for (y = 0; y < height; y++) {
|
||||||
|
for (x = 0; x < width / 8; x++) {
|
||||||
|
for (b = 7; b >= 0; b--) {
|
||||||
|
*ptr++ = buf[y * bytesPerRow + x] >> b & 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (b = 7; b > 7 - width % 8; b--) {
|
||||||
|
*ptr++ = buf[y * bytesPerRow + x] >> b & 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this software; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* hextile.c - handle hextile encoding.
|
||||||
|
*
|
||||||
|
* This file shouldn't be compiled directly. It is included multiple times by
|
||||||
|
* rfbproto.c, each time with a different definition of the macro BPP. For
|
||||||
|
* each value of BPP, this file defines a function which handles a hextile
|
||||||
|
* encoded rectangle with BPP bits per pixel.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define HandleHextileBPP CONCAT2E(HandleHextile,BPP)
|
||||||
|
#define CARDBPP CONCAT3E(uint,BPP,_t)
|
||||||
|
#define GET_PIXEL CONCAT2E(GET_PIXEL,BPP)
|
||||||
|
|
||||||
|
static Bool
|
||||||
|
HandleHextileBPP (rfbClient* client, int rx, int ry, int rw, int rh)
|
||||||
|
{
|
||||||
|
CARDBPP bg, fg;
|
||||||
|
int i;
|
||||||
|
uint8_t *ptr;
|
||||||
|
int x, y, w, h;
|
||||||
|
int sx, sy, sw, sh;
|
||||||
|
uint8_t subencoding;
|
||||||
|
uint8_t nSubrects;
|
||||||
|
|
||||||
|
for (y = ry; y < ry+rh; y += 16) {
|
||||||
|
for (x = rx; x < rx+rw; x += 16) {
|
||||||
|
w = h = 16;
|
||||||
|
if (rx+rw - x < 16)
|
||||||
|
w = rx+rw - x;
|
||||||
|
if (ry+rh - y < 16)
|
||||||
|
h = ry+rh - y;
|
||||||
|
|
||||||
|
if (!ReadFromRFBServer(client, (char *)&subencoding, 1))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (subencoding & rfbHextileRaw) {
|
||||||
|
if (!ReadFromRFBServer(client, client->buffer, w * h * (BPP / 8)))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
CopyRectangle(client, client->buffer, x, y, w, h);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subencoding & rfbHextileBackgroundSpecified)
|
||||||
|
if (!ReadFromRFBServer(client, (char *)&bg, sizeof(bg)))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
FillRectangle(client, x, y, w, h, fg);
|
||||||
|
|
||||||
|
if (subencoding & rfbHextileForegroundSpecified)
|
||||||
|
if (!ReadFromRFBServer(client, (char *)&fg, sizeof(fg)))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!(subencoding & rfbHextileAnySubrects)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ReadFromRFBServer(client, (char *)&nSubrects, 1))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
ptr = (uint8_t*)client->buffer;
|
||||||
|
|
||||||
|
if (subencoding & rfbHextileSubrectsColoured) {
|
||||||
|
if (!ReadFromRFBServer(client, client->buffer, nSubrects * (2 + (BPP / 8))))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
for (i = 0; i < nSubrects; i++) {
|
||||||
|
GET_PIXEL(fg, ptr);
|
||||||
|
sx = rfbHextileExtractX(*ptr);
|
||||||
|
sy = rfbHextileExtractY(*ptr);
|
||||||
|
ptr++;
|
||||||
|
sw = rfbHextileExtractW(*ptr);
|
||||||
|
sh = rfbHextileExtractH(*ptr);
|
||||||
|
ptr++;
|
||||||
|
|
||||||
|
FillRectangle(client, x+sx, y+sy, sw, sh, fg);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (!ReadFromRFBServer(client, client->buffer, nSubrects * 2))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
for (i = 0; i < nSubrects; i++) {
|
||||||
|
sx = rfbHextileExtractX(*ptr);
|
||||||
|
sy = rfbHextileExtractY(*ptr);
|
||||||
|
ptr++;
|
||||||
|
sw = rfbHextileExtractW(*ptr);
|
||||||
|
sh = rfbHextileExtractH(*ptr);
|
||||||
|
ptr++;
|
||||||
|
|
||||||
|
FillRectangle(client, x+sx, y+sy, sw, sh, fg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef CARDBPP
|
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this software; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* listen.c - listen for incoming connections
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
#include <rfb/rfbclient.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* listenForIncomingConnections() - listen for incoming connections from
|
||||||
|
* servers, and fork a new process to deal with each connection.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
listenForIncomingConnections(rfbClient* client)
|
||||||
|
{
|
||||||
|
int listenSocket;
|
||||||
|
fd_set fds;
|
||||||
|
|
||||||
|
client->listenSpecified = TRUE;
|
||||||
|
|
||||||
|
listenSocket = ListenAtTcpPort(client->listenPort);
|
||||||
|
|
||||||
|
if ((listenSocket < 0)) exit(1);
|
||||||
|
|
||||||
|
fprintf(stderr,"%s -listen: Listening on port %d\n",
|
||||||
|
client->programName,client->listenPort);
|
||||||
|
fprintf(stderr,"%s -listen: Command line errors are not reported until "
|
||||||
|
"a connection comes in.\n", client->programName);
|
||||||
|
|
||||||
|
while (TRUE) {
|
||||||
|
|
||||||
|
/* reap any zombies */
|
||||||
|
int status, pid;
|
||||||
|
while ((pid= wait3(&status, WNOHANG, (struct rusage *)0))>0);
|
||||||
|
|
||||||
|
/* TODO: callback for discard any events (like X11 events) */
|
||||||
|
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
|
||||||
|
FD_SET(listenSocket, &fds);
|
||||||
|
|
||||||
|
select(FD_SETSIZE, &fds, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
if (FD_ISSET(listenSocket, &fds)) {
|
||||||
|
client->sock = AcceptTcpConnection(listenSocket);
|
||||||
|
if (client->sock < 0) exit(1);
|
||||||
|
if (!SetNonBlocking(client->sock)) exit(1);
|
||||||
|
|
||||||
|
/* Now fork off a new process to deal with it... */
|
||||||
|
|
||||||
|
switch (fork()) {
|
||||||
|
|
||||||
|
case -1:
|
||||||
|
perror("fork");
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
/* child - return to caller */
|
||||||
|
close(listenSocket);
|
||||||
|
return;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* parent - go round and listen again */
|
||||||
|
close(client->sock);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this software; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* rre.c - handle RRE encoding.
|
||||||
|
*
|
||||||
|
* This file shouldn't be compiled directly. It is included multiple times by
|
||||||
|
* rfbproto.c, each time with a different definition of the macro BPP. For
|
||||||
|
* each value of BPP, this file defines a function which handles an RRE
|
||||||
|
* encoded rectangle with BPP bits per pixel.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define HandleRREBPP CONCAT2E(HandleRRE,BPP)
|
||||||
|
#define CARDBPP CONCAT3E(uint,BPP,_t)
|
||||||
|
|
||||||
|
static Bool
|
||||||
|
HandleRREBPP (rfbClient* client, int rx, int ry, int rw, int rh)
|
||||||
|
{
|
||||||
|
rfbRREHeader hdr;
|
||||||
|
int i;
|
||||||
|
CARDBPP pix;
|
||||||
|
rfbRectangle subrect;
|
||||||
|
|
||||||
|
if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbRREHeader))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
hdr.nSubrects = Swap32IfLE(hdr.nSubrects);
|
||||||
|
|
||||||
|
if (!ReadFromRFBServer(client, (char *)&pix, sizeof(pix)))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
FillRectangle(client, rx, ry, rw, rh, pix);
|
||||||
|
|
||||||
|
for (i = 0; i < hdr.nSubrects; i++) {
|
||||||
|
if (!ReadFromRFBServer(client, (char *)&pix, sizeof(pix)))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!ReadFromRFBServer(client, (char *)&subrect, sz_rfbRectangle))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
subrect.x = Swap16IfLE(subrect.x);
|
||||||
|
subrect.y = Swap16IfLE(subrect.y);
|
||||||
|
subrect.w = Swap16IfLE(subrect.w);
|
||||||
|
subrect.h = Swap16IfLE(subrect.h);
|
||||||
|
|
||||||
|
FillRectangle(client, rx+subrect.x, ry+subrect.y, subrect.w, subrect.h, pix);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef CARDBPP
|
@ -0,0 +1,424 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this software; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* sockets.c - functions to deal with sockets.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <rfb/rfbclient.h>
|
||||||
|
|
||||||
|
void PrintInHex(char *buf, int len);
|
||||||
|
|
||||||
|
Bool errorMessageOnReadFailure = TRUE;
|
||||||
|
|
||||||
|
#define BUF_SIZE 8192
|
||||||
|
static char buf[BUF_SIZE];
|
||||||
|
static char *bufoutptr = buf;
|
||||||
|
static int buffered = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ReadFromRFBServer is called whenever we want to read some data from the RFB
|
||||||
|
* server. It is non-trivial for two reasons:
|
||||||
|
*
|
||||||
|
* 1. For efficiency it performs some intelligent buffering, avoiding invoking
|
||||||
|
* the read() system call too often. For small chunks of data, it simply
|
||||||
|
* copies the data out of an internal buffer. For large amounts of data it
|
||||||
|
* reads directly into the buffer provided by the caller.
|
||||||
|
*
|
||||||
|
* 2. Whenever read() would block, it invokes the Xt event dispatching
|
||||||
|
* mechanism to process X events. In fact, this is the only place these
|
||||||
|
* events are processed, as there is no XtAppMainLoop in the program.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Bool
|
||||||
|
ReadFromRFBServer(rfbClient* client, char *out, unsigned int n)
|
||||||
|
{
|
||||||
|
if (n <= buffered) {
|
||||||
|
memcpy(out, bufoutptr, n);
|
||||||
|
bufoutptr += n;
|
||||||
|
buffered -= n;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(out, bufoutptr, buffered);
|
||||||
|
|
||||||
|
out += buffered;
|
||||||
|
n -= buffered;
|
||||||
|
|
||||||
|
bufoutptr = buf;
|
||||||
|
buffered = 0;
|
||||||
|
|
||||||
|
if (n <= BUF_SIZE) {
|
||||||
|
|
||||||
|
while (buffered < n) {
|
||||||
|
int i = read(client->sock, buf + buffered, BUF_SIZE - buffered);
|
||||||
|
if (i <= 0) {
|
||||||
|
if (i < 0) {
|
||||||
|
if (errno == EWOULDBLOCK || errno == EAGAIN) {
|
||||||
|
/* TODO:
|
||||||
|
ProcessXtEvents();
|
||||||
|
*/
|
||||||
|
i = 0;
|
||||||
|
} else {
|
||||||
|
perror("read");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (errorMessageOnReadFailure) {
|
||||||
|
fprintf(stderr,"VNC server closed connection\n");
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buffered += i;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(out, bufoutptr, n);
|
||||||
|
bufoutptr += n;
|
||||||
|
buffered -= n;
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
while (n > 0) {
|
||||||
|
int i = read(client->sock, out, n);
|
||||||
|
if (i <= 0) {
|
||||||
|
if (i < 0) {
|
||||||
|
if (errno == EWOULDBLOCK || errno == EAGAIN) {
|
||||||
|
/* TODO:
|
||||||
|
ProcessXtEvents();
|
||||||
|
*/
|
||||||
|
i = 0;
|
||||||
|
} else {
|
||||||
|
perror("read");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (errorMessageOnReadFailure) {
|
||||||
|
fprintf(stderr,"VNC server closed connection\n");
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out += i;
|
||||||
|
n -= i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write an exact number of bytes, and don't return until you've sent them.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Bool
|
||||||
|
WriteExact(rfbClient* client, char *buf, int n)
|
||||||
|
{
|
||||||
|
fd_set fds;
|
||||||
|
int i = 0;
|
||||||
|
int j;
|
||||||
|
|
||||||
|
while (i < n) {
|
||||||
|
j = write(client->sock, buf + i, (n - i));
|
||||||
|
if (j <= 0) {
|
||||||
|
if (j < 0) {
|
||||||
|
if (errno == EWOULDBLOCK || errno == EAGAIN) {
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(client->sock,&fds);
|
||||||
|
|
||||||
|
if (select(client->sock+1, NULL, &fds, NULL, NULL) <= 0) {
|
||||||
|
perror("select");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
j = 0;
|
||||||
|
} else {
|
||||||
|
perror("write");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stderr,"write failed\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i += j;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ConnectToTcpAddr connects to the given TCP port.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
ConnectToTcpAddr(unsigned int host, int port)
|
||||||
|
{
|
||||||
|
int sock;
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
int one = 1;
|
||||||
|
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons(port);
|
||||||
|
addr.sin_addr.s_addr = host;
|
||||||
|
|
||||||
|
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (sock < 0) {
|
||||||
|
perror("ConnectToTcpAddr: socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||||
|
perror("ConnectToTcpAddr: connect");
|
||||||
|
close(sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
|
||||||
|
(char *)&one, sizeof(one)) < 0) {
|
||||||
|
perror("ConnectToTcpAddr: setsockopt");
|
||||||
|
close(sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FindFreeTcpPort tries to find unused TCP port in the range
|
||||||
|
* (TUNNEL_PORT_OFFSET, TUNNEL_PORT_OFFSET + 99]. Returns 0 on failure.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
FindFreeTcpPort(void)
|
||||||
|
{
|
||||||
|
int sock, port;
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
|
||||||
|
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (sock < 0) {
|
||||||
|
perror(": FindFreeTcpPort: socket");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (port = TUNNEL_PORT_OFFSET + 99; port > TUNNEL_PORT_OFFSET; port--) {
|
||||||
|
addr.sin_port = htons((unsigned short)port);
|
||||||
|
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
|
||||||
|
close(sock);
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(sock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ListenAtTcpPort starts listening at the given TCP port.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
ListenAtTcpPort(int port)
|
||||||
|
{
|
||||||
|
int sock;
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
int one = 1;
|
||||||
|
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons(port);
|
||||||
|
addr.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
|
||||||
|
sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (sock < 0) {
|
||||||
|
perror("ListenAtTcpPort: socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
|
||||||
|
(const char *)&one, sizeof(one)) < 0) {
|
||||||
|
perror("ListenAtTcpPort: setsockopt");
|
||||||
|
close(sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||||
|
perror("ListenAtTcpPort: bind");
|
||||||
|
close(sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(sock, 5) < 0) {
|
||||||
|
perror("ListenAtTcpPort: listen");
|
||||||
|
close(sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AcceptTcpConnection accepts a TCP connection.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
AcceptTcpConnection(int listenSock)
|
||||||
|
{
|
||||||
|
int sock;
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
int addrlen = sizeof(addr);
|
||||||
|
int one = 1;
|
||||||
|
|
||||||
|
sock = accept(listenSock, (struct sockaddr *) &addr, &addrlen);
|
||||||
|
if (sock < 0) {
|
||||||
|
perror("AcceptTcpConnection: accept");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
|
||||||
|
(char *)&one, sizeof(one)) < 0) {
|
||||||
|
perror("AcceptTcpConnection: setsockopt");
|
||||||
|
close(sock);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sock;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SetNonBlocking sets a socket into non-blocking mode.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Bool
|
||||||
|
SetNonBlocking(int sock)
|
||||||
|
{
|
||||||
|
if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
|
||||||
|
perror("AcceptTcpConnection: fcntl");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* StringToIPAddr - convert a host string to an IP address.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Bool
|
||||||
|
StringToIPAddr(const char *str, unsigned int *addr)
|
||||||
|
{
|
||||||
|
struct hostent *hp;
|
||||||
|
|
||||||
|
if (strcmp(str,"") == 0) {
|
||||||
|
*addr = 0; /* local */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*addr = inet_addr(str);
|
||||||
|
|
||||||
|
if (*addr != -1)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
hp = gethostbyname(str);
|
||||||
|
|
||||||
|
if (hp) {
|
||||||
|
*addr = *(unsigned int *)hp->h_addr;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test if the other end of a socket is on the same machine.
|
||||||
|
*/
|
||||||
|
|
||||||
|
Bool
|
||||||
|
SameMachine(int sock)
|
||||||
|
{
|
||||||
|
struct sockaddr_in peeraddr, myaddr;
|
||||||
|
int addrlen = sizeof(struct sockaddr_in);
|
||||||
|
|
||||||
|
getpeername(sock, (struct sockaddr *)&peeraddr, &addrlen);
|
||||||
|
getsockname(sock, (struct sockaddr *)&myaddr, &addrlen);
|
||||||
|
|
||||||
|
return (peeraddr.sin_addr.s_addr == myaddr.sin_addr.s_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print out the contents of a packet for debugging.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
PrintInHex(char *buf, int len)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
char c, str[17];
|
||||||
|
|
||||||
|
str[16] = 0;
|
||||||
|
|
||||||
|
fprintf(stderr,"ReadExact: ");
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
if ((i % 16 == 0) && (i != 0)) {
|
||||||
|
fprintf(stderr," ");
|
||||||
|
}
|
||||||
|
c = buf[i];
|
||||||
|
str[i % 16] = (((c > 31) && (c < 127)) ? c : '.');
|
||||||
|
fprintf(stderr,"%02x ",(unsigned char)c);
|
||||||
|
if ((i % 4) == 3)
|
||||||
|
fprintf(stderr," ");
|
||||||
|
if ((i % 16) == 15)
|
||||||
|
{
|
||||||
|
fprintf(stderr,"%s\n",str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((i % 16) != 0)
|
||||||
|
{
|
||||||
|
for (j = i % 16; j < 16; j++)
|
||||||
|
{
|
||||||
|
fprintf(stderr," ");
|
||||||
|
if ((j % 4) == 3) fprintf(stderr," ");
|
||||||
|
}
|
||||||
|
str[i % 16] = 0;
|
||||||
|
fprintf(stderr,"%s\n",str);
|
||||||
|
}
|
||||||
|
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
@ -0,0 +1,606 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this software; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* tight.c - handle ``tight'' encoding.
|
||||||
|
*
|
||||||
|
* This file shouldn't be compiled directly. It is included multiple
|
||||||
|
* times by rfbproto.c, each time with a different definition of the
|
||||||
|
* macro BPP. For each value of BPP, this file defines a function
|
||||||
|
* which handles a tight-encoded rectangle with BPP bits per pixel.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define TIGHT_MIN_TO_COMPRESS 12
|
||||||
|
|
||||||
|
#define CARDBPP CONCAT3E(uint,BPP,_t)
|
||||||
|
#define filterPtrBPP CONCAT2E(filterPtr,BPP)
|
||||||
|
|
||||||
|
#define HandleTightBPP CONCAT2E(HandleTight,BPP)
|
||||||
|
#define InitFilterCopyBPP CONCAT2E(InitFilterCopy,BPP)
|
||||||
|
#define InitFilterPaletteBPP CONCAT2E(InitFilterPalette,BPP)
|
||||||
|
#define InitFilterGradientBPP CONCAT2E(InitFilterGradient,BPP)
|
||||||
|
#define FilterCopyBPP CONCAT2E(FilterCopy,BPP)
|
||||||
|
#define FilterPaletteBPP CONCAT2E(FilterPalette,BPP)
|
||||||
|
#define FilterGradientBPP CONCAT2E(FilterGradient,BPP)
|
||||||
|
|
||||||
|
#if BPP != 8
|
||||||
|
#define DecompressJpegRectBPP CONCAT2E(DecompressJpegRect,BPP)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RGB_TO_PIXEL
|
||||||
|
|
||||||
|
#define RGB_TO_PIXEL(bpp,r,g,b) \
|
||||||
|
(((CARD##bpp)(r) & client->format.redMax) << client->format.redShift | \
|
||||||
|
((CARD##bpp)(g) & client->format.greenMax) << client->format.greenShift | \
|
||||||
|
((CARD##bpp)(b) & client->format.blueMax) << client->format.blueShift)
|
||||||
|
|
||||||
|
#define RGB24_TO_PIXEL(bpp,r,g,b) \
|
||||||
|
((((CARD##bpp)(r) & 0xFF) * client->format.redMax + 127) / 255 \
|
||||||
|
<< client->format.redShift | \
|
||||||
|
(((CARD##bpp)(g) & 0xFF) * client->format.greenMax + 127) / 255 \
|
||||||
|
<< client->format.greenShift | \
|
||||||
|
(((CARD##bpp)(b) & 0xFF) * client->format.blueMax + 127) / 255 \
|
||||||
|
<< client->format.blueShift)
|
||||||
|
|
||||||
|
#define RGB24_TO_PIXEL32(r,g,b) \
|
||||||
|
(((uint32_t)(r) & 0xFF) << client->format.redShift | \
|
||||||
|
((uint32_t)(g) & 0xFF) << client->format.greenShift | \
|
||||||
|
((uint32_t)(b) & 0xFF) << client->format.blueShift)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Type declarations */
|
||||||
|
|
||||||
|
typedef void (*filterPtrBPP)(rfbClient* client, int, CARDBPP *);
|
||||||
|
|
||||||
|
/* Prototypes */
|
||||||
|
|
||||||
|
static int InitFilterCopyBPP (rfbClient* client, int rw, int rh);
|
||||||
|
static int InitFilterPaletteBPP (rfbClient* client, int rw, int rh);
|
||||||
|
static int InitFilterGradientBPP (rfbClient* client, int rw, int rh);
|
||||||
|
static void FilterCopyBPP (rfbClient* client, int numRows, CARDBPP *destBuffer);
|
||||||
|
static void FilterPaletteBPP (rfbClient* client, int numRows, CARDBPP *destBuffer);
|
||||||
|
static void FilterGradientBPP (rfbClient* client, int numRows, CARDBPP *destBuffer);
|
||||||
|
|
||||||
|
#if BPP != 8
|
||||||
|
static Bool DecompressJpegRectBPP(rfbClient* client, int x, int y, int w, int h);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Definitions */
|
||||||
|
|
||||||
|
static Bool
|
||||||
|
HandleTightBPP (rfbClient* client, int rx, int ry, int rw, int rh)
|
||||||
|
{
|
||||||
|
CARDBPP fill_colour;
|
||||||
|
uint8_t comp_ctl;
|
||||||
|
uint8_t filter_id;
|
||||||
|
filterPtrBPP filterFn;
|
||||||
|
z_streamp zs;
|
||||||
|
char *buffer2;
|
||||||
|
int err, stream_id, compressedLen, bitsPixel;
|
||||||
|
int bufferSize, rowSize, numRows, portionLen, rowsProcessed, extraBytes;
|
||||||
|
|
||||||
|
if (!ReadFromRFBServer(client, (char *)&comp_ctl, 1))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* Flush zlib streams if we are told by the server to do so. */
|
||||||
|
for (stream_id = 0; stream_id < 4; stream_id++) {
|
||||||
|
if ((comp_ctl & 1) && zlibStreamActive[stream_id]) {
|
||||||
|
if (inflateEnd (&zlibStream[stream_id]) != Z_OK &&
|
||||||
|
zlibStream[stream_id].msg != NULL)
|
||||||
|
fprintf(stderr, "inflateEnd: %s\n", zlibStream[stream_id].msg);
|
||||||
|
zlibStreamActive[stream_id] = FALSE;
|
||||||
|
}
|
||||||
|
comp_ctl >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle solid rectangles. */
|
||||||
|
if (comp_ctl == rfbTightFill) {
|
||||||
|
#if BPP == 32
|
||||||
|
if (client->format.depth == 24 && client->format.redMax == 0xFF &&
|
||||||
|
client->format.greenMax == 0xFF && client->format.blueMax == 0xFF) {
|
||||||
|
if (!ReadFromRFBServer(client, client->buffer, 3))
|
||||||
|
return FALSE;
|
||||||
|
fill_colour = RGB24_TO_PIXEL32(client->buffer[0], client->buffer[1], client->buffer[2]);
|
||||||
|
} else {
|
||||||
|
if (!ReadFromRFBServer(client, (char*)&fill_colour, sizeof(fill_colour)))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (!ReadFromRFBServer(client, (char*)&fill_colour, sizeof(fill_colour)))
|
||||||
|
return FALSE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FillRectangle(client, rx, ry, rw, rh, fill_colour);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BPP == 8
|
||||||
|
if (comp_ctl == rfbTightJpeg) {
|
||||||
|
fprintf(stderr, "Tight encoding: JPEG is not supported in 8 bpp mode.\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (comp_ctl == rfbTightJpeg) {
|
||||||
|
return DecompressJpegRectBPP(client, rx, ry, rw, rh);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Quit on unsupported subencoding value. */
|
||||||
|
if (comp_ctl > rfbTightMaxSubencoding) {
|
||||||
|
fprintf(stderr, "Tight encoding: bad subencoding value received.\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Here primary compression mode handling begins.
|
||||||
|
* Data was processed with optional filter + zlib compression.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* First, we should identify a filter to use. */
|
||||||
|
if ((comp_ctl & rfbTightExplicitFilter) != 0) {
|
||||||
|
if (!ReadFromRFBServer(client, (char*)&filter_id, 1))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
switch (filter_id) {
|
||||||
|
case rfbTightFilterCopy:
|
||||||
|
filterFn = FilterCopyBPP;
|
||||||
|
bitsPixel = InitFilterCopyBPP(client, rw, rh);
|
||||||
|
break;
|
||||||
|
case rfbTightFilterPalette:
|
||||||
|
filterFn = FilterPaletteBPP;
|
||||||
|
bitsPixel = InitFilterPaletteBPP(client, rw, rh);
|
||||||
|
break;
|
||||||
|
case rfbTightFilterGradient:
|
||||||
|
filterFn = FilterGradientBPP;
|
||||||
|
bitsPixel = InitFilterGradientBPP(client, rw, rh);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Tight encoding: unknown filter code received.\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
filterFn = FilterCopyBPP;
|
||||||
|
bitsPixel = InitFilterCopyBPP(client, rw, rh);
|
||||||
|
}
|
||||||
|
if (bitsPixel == 0) {
|
||||||
|
fprintf(stderr, "Tight encoding: error receiving palette.\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determine if the data should be decompressed or just copied. */
|
||||||
|
rowSize = (rw * bitsPixel + 7) / 8;
|
||||||
|
if (rh * rowSize < TIGHT_MIN_TO_COMPRESS) {
|
||||||
|
if (!ReadFromRFBServer(client, (char*)client->buffer, rh * rowSize))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
buffer2 = &client->buffer[TIGHT_MIN_TO_COMPRESS * 4];
|
||||||
|
filterFn(client, rh, (CARDBPP *)buffer2);
|
||||||
|
|
||||||
|
CopyRectangle(client, buffer2, rx, ry, rw, rh);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the length (1..3 bytes) of compressed data following. */
|
||||||
|
compressedLen = (int)ReadCompactLen(client);
|
||||||
|
if (compressedLen <= 0) {
|
||||||
|
fprintf(stderr, "Incorrect data received from the server.\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now let's initialize compression stream if needed. */
|
||||||
|
stream_id = comp_ctl & 0x03;
|
||||||
|
zs = &zlibStream[stream_id];
|
||||||
|
if (!zlibStreamActive[stream_id]) {
|
||||||
|
zs->zalloc = Z_NULL;
|
||||||
|
zs->zfree = Z_NULL;
|
||||||
|
zs->opaque = Z_NULL;
|
||||||
|
err = inflateInit(zs);
|
||||||
|
if (err != Z_OK) {
|
||||||
|
if (zs->msg != NULL)
|
||||||
|
fprintf(stderr, "InflateInit error: %s.\n", zs->msg);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
zlibStreamActive[stream_id] = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read, decode and draw actual pixel data in a loop. */
|
||||||
|
|
||||||
|
bufferSize = BUFFER_SIZE * bitsPixel / (bitsPixel + BPP) & 0xFFFFFFFC;
|
||||||
|
buffer2 = &client->buffer[bufferSize];
|
||||||
|
if (rowSize > bufferSize) {
|
||||||
|
/* Should be impossible when BUFFER_SIZE >= 16384 */
|
||||||
|
fprintf(stderr, "Internal error: incorrect buffer size.\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
rowsProcessed = 0;
|
||||||
|
extraBytes = 0;
|
||||||
|
|
||||||
|
while (compressedLen > 0) {
|
||||||
|
if (compressedLen > ZLIB_BUFFER_SIZE)
|
||||||
|
portionLen = ZLIB_BUFFER_SIZE;
|
||||||
|
else
|
||||||
|
portionLen = compressedLen;
|
||||||
|
|
||||||
|
if (!ReadFromRFBServer(client, (char*)zlib_buffer, portionLen))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
compressedLen -= portionLen;
|
||||||
|
|
||||||
|
zs->next_in = (Bytef *)zlib_buffer;
|
||||||
|
zs->avail_in = portionLen;
|
||||||
|
|
||||||
|
do {
|
||||||
|
zs->next_out = (Bytef *)&client->buffer[extraBytes];
|
||||||
|
zs->avail_out = bufferSize - extraBytes;
|
||||||
|
|
||||||
|
err = inflate(zs, Z_SYNC_FLUSH);
|
||||||
|
if (err == Z_BUF_ERROR) /* Input exhausted -- no problem. */
|
||||||
|
break;
|
||||||
|
if (err != Z_OK && err != Z_STREAM_END) {
|
||||||
|
if (zs->msg != NULL) {
|
||||||
|
fprintf(stderr, "Inflate error: %s.\n", zs->msg);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Inflate error: %d.\n", err);
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
numRows = (bufferSize - zs->avail_out) / rowSize;
|
||||||
|
|
||||||
|
filterFn(client, numRows, (CARDBPP *)buffer2);
|
||||||
|
|
||||||
|
extraBytes = bufferSize - zs->avail_out - numRows * rowSize;
|
||||||
|
if (extraBytes > 0)
|
||||||
|
memcpy(client->buffer, &client->buffer[numRows * rowSize], extraBytes);
|
||||||
|
|
||||||
|
CopyRectangle(client, buffer2, rx, ry+rowsProcessed, rw, numRows);
|
||||||
|
|
||||||
|
rowsProcessed += numRows;
|
||||||
|
}
|
||||||
|
while (zs->avail_out == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rowsProcessed != rh) {
|
||||||
|
fprintf(stderr, "Incorrect number of scan lines after decompression.\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* Filter stuff.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
The following variables are defined in rfbproto.c:
|
||||||
|
static Bool cutZeros;
|
||||||
|
static int rectWidth, rectColors;
|
||||||
|
static uint8_t tightPalette[256*4];
|
||||||
|
static uint8_t tightPrevRow[2048*3*sizeof(CARD16)];
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int
|
||||||
|
InitFilterCopyBPP (rfbClient* client, int rw, int rh)
|
||||||
|
{
|
||||||
|
rectWidth = rw;
|
||||||
|
|
||||||
|
#if BPP == 32
|
||||||
|
if (client->format.depth == 24 && client->format.redMax == 0xFF &&
|
||||||
|
client->format.greenMax == 0xFF && client->format.blueMax == 0xFF) {
|
||||||
|
cutZeros = TRUE;
|
||||||
|
return 24;
|
||||||
|
} else {
|
||||||
|
cutZeros = FALSE;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return BPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
FilterCopyBPP (rfbClient* client, int numRows, CARDBPP *dst)
|
||||||
|
{
|
||||||
|
|
||||||
|
#if BPP == 32
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
if (cutZeros) {
|
||||||
|
for (y = 0; y < numRows; y++) {
|
||||||
|
for (x = 0; x < rectWidth; x++) {
|
||||||
|
dst[y*rectWidth+x] =
|
||||||
|
RGB24_TO_PIXEL32(client->buffer[(y*rectWidth+x)*3],
|
||||||
|
client->buffer[(y*rectWidth+x)*3+1],
|
||||||
|
client->buffer[(y*rectWidth+x)*3+2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
memcpy (dst, client->buffer, numRows * rectWidth * (BPP / 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
InitFilterGradientBPP (rfbClient* client, int rw, int rh)
|
||||||
|
{
|
||||||
|
int bits;
|
||||||
|
|
||||||
|
bits = InitFilterCopyBPP(client, rw, rh);
|
||||||
|
if (cutZeros)
|
||||||
|
memset(tightPrevRow, 0, rw * 3);
|
||||||
|
else
|
||||||
|
memset(tightPrevRow, 0, rw * 3 * sizeof(uint16_t));
|
||||||
|
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BPP == 32
|
||||||
|
|
||||||
|
static void
|
||||||
|
FilterGradient24 (rfbClient* client, int numRows, uint32_t *dst)
|
||||||
|
{
|
||||||
|
int x, y, c;
|
||||||
|
uint8_t thisRow[2048*3];
|
||||||
|
uint8_t pix[3];
|
||||||
|
int est[3];
|
||||||
|
|
||||||
|
for (y = 0; y < numRows; y++) {
|
||||||
|
|
||||||
|
/* First pixel in a row */
|
||||||
|
for (c = 0; c < 3; c++) {
|
||||||
|
pix[c] = tightPrevRow[c] + client->buffer[y*rectWidth*3+c];
|
||||||
|
thisRow[c] = pix[c];
|
||||||
|
}
|
||||||
|
dst[y*rectWidth] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
|
||||||
|
|
||||||
|
/* Remaining pixels of a row */
|
||||||
|
for (x = 1; x < rectWidth; x++) {
|
||||||
|
for (c = 0; c < 3; c++) {
|
||||||
|
est[c] = (int)tightPrevRow[x*3+c] + (int)pix[c] -
|
||||||
|
(int)tightPrevRow[(x-1)*3+c];
|
||||||
|
if (est[c] > 0xFF) {
|
||||||
|
est[c] = 0xFF;
|
||||||
|
} else if (est[c] < 0x00) {
|
||||||
|
est[c] = 0x00;
|
||||||
|
}
|
||||||
|
pix[c] = (uint8_t)est[c] + client->buffer[(y*rectWidth+x)*3+c];
|
||||||
|
thisRow[x*3+c] = pix[c];
|
||||||
|
}
|
||||||
|
dst[y*rectWidth+x] = RGB24_TO_PIXEL32(pix[0], pix[1], pix[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(tightPrevRow, thisRow, rectWidth * 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
FilterGradientBPP (rfbClient* client, int numRows, CARDBPP *dst)
|
||||||
|
{
|
||||||
|
int x, y, c;
|
||||||
|
CARDBPP *src = (CARDBPP *)client->buffer;
|
||||||
|
uint16_t *thatRow = (uint16_t *)tightPrevRow;
|
||||||
|
uint16_t thisRow[2048*3];
|
||||||
|
uint16_t pix[3];
|
||||||
|
uint16_t max[3];
|
||||||
|
int shift[3];
|
||||||
|
int est[3];
|
||||||
|
|
||||||
|
#if BPP == 32
|
||||||
|
if (cutZeros) {
|
||||||
|
FilterGradient24(client, numRows, dst);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
max[0] = client->format.redMax;
|
||||||
|
max[1] = client->format.greenMax;
|
||||||
|
max[2] = client->format.blueMax;
|
||||||
|
|
||||||
|
shift[0] = client->format.redShift;
|
||||||
|
shift[1] = client->format.greenShift;
|
||||||
|
shift[2] = client->format.blueShift;
|
||||||
|
|
||||||
|
for (y = 0; y < numRows; y++) {
|
||||||
|
|
||||||
|
/* First pixel in a row */
|
||||||
|
for (c = 0; c < 3; c++) {
|
||||||
|
pix[c] = (uint16_t)(((src[y*rectWidth] >> shift[c]) + thatRow[c]) & max[c]);
|
||||||
|
thisRow[c] = pix[c];
|
||||||
|
}
|
||||||
|
dst[y*rectWidth] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]);
|
||||||
|
|
||||||
|
/* Remaining pixels of a row */
|
||||||
|
for (x = 1; x < rectWidth; x++) {
|
||||||
|
for (c = 0; c < 3; c++) {
|
||||||
|
est[c] = (int)thatRow[x*3+c] + (int)pix[c] - (int)thatRow[(x-1)*3+c];
|
||||||
|
if (est[c] > (int)max[c]) {
|
||||||
|
est[c] = (int)max[c];
|
||||||
|
} else if (est[c] < 0) {
|
||||||
|
est[c] = 0;
|
||||||
|
}
|
||||||
|
pix[c] = (uint16_t)(((src[y*rectWidth+x] >> shift[c]) + est[c]) & max[c]);
|
||||||
|
thisRow[x*3+c] = pix[c];
|
||||||
|
}
|
||||||
|
dst[y*rectWidth+x] = RGB_TO_PIXEL(BPP, pix[0], pix[1], pix[2]);
|
||||||
|
}
|
||||||
|
memcpy(thatRow, thisRow, rectWidth * 3 * sizeof(uint16_t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
InitFilterPaletteBPP (rfbClient* client, int rw, int rh)
|
||||||
|
{
|
||||||
|
uint8_t numColors;
|
||||||
|
#if BPP == 32
|
||||||
|
int i;
|
||||||
|
CARDBPP *palette = (CARDBPP *)tightPalette;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
rectWidth = rw;
|
||||||
|
|
||||||
|
if (!ReadFromRFBServer(client, (char*)&numColors, 1))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
rectColors = (int)numColors;
|
||||||
|
if (++rectColors < 2)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
#if BPP == 32
|
||||||
|
if (client->format.depth == 24 && client->format.redMax == 0xFF &&
|
||||||
|
client->format.greenMax == 0xFF && client->format.blueMax == 0xFF) {
|
||||||
|
if (!ReadFromRFBServer(client, (char*)&tightPalette, rectColors * 3))
|
||||||
|
return 0;
|
||||||
|
for (i = rectColors - 1; i >= 0; i--) {
|
||||||
|
palette[i] = RGB24_TO_PIXEL32(tightPalette[i*3],
|
||||||
|
tightPalette[i*3+1],
|
||||||
|
tightPalette[i*3+2]);
|
||||||
|
}
|
||||||
|
return (rectColors == 2) ? 1 : 8;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!ReadFromRFBServer(client, (char*)&tightPalette, rectColors * (BPP / 8)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (rectColors == 2) ? 1 : 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
FilterPaletteBPP (rfbClient* client, int numRows, CARDBPP *dst)
|
||||||
|
{
|
||||||
|
int x, y, b, w;
|
||||||
|
uint8_t *src = (uint8_t *)client->buffer;
|
||||||
|
CARDBPP *palette = (CARDBPP *)tightPalette;
|
||||||
|
|
||||||
|
if (rectColors == 2) {
|
||||||
|
w = (rectWidth + 7) / 8;
|
||||||
|
for (y = 0; y < numRows; y++) {
|
||||||
|
for (x = 0; x < rectWidth / 8; x++) {
|
||||||
|
for (b = 7; b >= 0; b--)
|
||||||
|
dst[y*rectWidth+x*8+7-b] = palette[src[y*w+x] >> b & 1];
|
||||||
|
}
|
||||||
|
for (b = 7; b >= 8 - rectWidth % 8; b--) {
|
||||||
|
dst[y*rectWidth+x*8+7-b] = palette[src[y*w+x] >> b & 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (y = 0; y < numRows; y++)
|
||||||
|
for (x = 0; x < rectWidth; x++)
|
||||||
|
dst[y*rectWidth+x] = palette[(int)src[y*rectWidth+x]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BPP != 8
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* JPEG decompression.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
The following variables are defined in rfbproto.c:
|
||||||
|
static Bool jpegError;
|
||||||
|
static struct jpeg_source_mgr jpegSrcManager;
|
||||||
|
static JOCTET *jpegBufferPtr;
|
||||||
|
static size_t *jpegBufferLen;
|
||||||
|
*/
|
||||||
|
|
||||||
|
static Bool
|
||||||
|
DecompressJpegRectBPP(rfbClient* client, int x, int y, int w, int h)
|
||||||
|
{
|
||||||
|
struct jpeg_decompress_struct cinfo;
|
||||||
|
struct jpeg_error_mgr jerr;
|
||||||
|
int compressedLen;
|
||||||
|
uint8_t *compressedData;
|
||||||
|
CARDBPP *pixelPtr;
|
||||||
|
JSAMPROW rowPointer[1];
|
||||||
|
int dx, dy;
|
||||||
|
|
||||||
|
compressedLen = (int)ReadCompactLen(client);
|
||||||
|
if (compressedLen <= 0) {
|
||||||
|
fprintf(stderr, "Incorrect data received from the server.\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
compressedData = malloc(compressedLen);
|
||||||
|
if (compressedData == NULL) {
|
||||||
|
fprintf(stderr, "Memory allocation error.\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ReadFromRFBServer(client, (char*)compressedData, compressedLen)) {
|
||||||
|
free(compressedData);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
cinfo.err = jpeg_std_error(&jerr);
|
||||||
|
jpeg_create_decompress(&cinfo);
|
||||||
|
|
||||||
|
JpegSetSrcManager(&cinfo, compressedData, compressedLen);
|
||||||
|
|
||||||
|
jpeg_read_header(&cinfo, TRUE);
|
||||||
|
cinfo.out_color_space = JCS_RGB;
|
||||||
|
|
||||||
|
jpeg_start_decompress(&cinfo);
|
||||||
|
if (cinfo.output_width != w || cinfo.output_height != h ||
|
||||||
|
cinfo.output_components != 3) {
|
||||||
|
fprintf(stderr, "Tight Encoding: Wrong JPEG data received.\n");
|
||||||
|
jpeg_destroy_decompress(&cinfo);
|
||||||
|
free(compressedData);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
rowPointer[0] = (JSAMPROW)client->buffer;
|
||||||
|
dy = 0;
|
||||||
|
while (cinfo.output_scanline < cinfo.output_height) {
|
||||||
|
jpeg_read_scanlines(&cinfo, rowPointer, 1);
|
||||||
|
if (jpegError) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pixelPtr = (CARDBPP *)&client->buffer[BUFFER_SIZE / 2];
|
||||||
|
for (dx = 0; dx < w; dx++) {
|
||||||
|
*pixelPtr++ =
|
||||||
|
RGB24_TO_PIXEL(BPP, client->buffer[dx*3], client->buffer[dx*3+1], client->buffer[dx*3+2]);
|
||||||
|
}
|
||||||
|
CopyRectangle(client, &client->buffer[BUFFER_SIZE / 2], x, y + dy, w, 1);
|
||||||
|
dy++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!jpegError)
|
||||||
|
jpeg_finish_decompress(&cinfo);
|
||||||
|
|
||||||
|
jpeg_destroy_decompress(&cinfo);
|
||||||
|
free(compressedData);
|
||||||
|
|
||||||
|
return !jpegError;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,240 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this software; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* vncviewer.c - the Xt-based VNC viewer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <rfb/rfbclient.h>
|
||||||
|
|
||||||
|
static void Dummy(rfbClient* client) {
|
||||||
|
}
|
||||||
|
static Bool DummyPoint(rfbClient* client, int x, int y) {
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
static void DummyRect(rfbClient* client, int x, int y, int w, int h) {
|
||||||
|
}
|
||||||
|
static char* NoPassword(rfbClient* client) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
static Bool MallocFrameBuffer(rfbClient* client) {
|
||||||
|
if(client->frameBuffer)
|
||||||
|
free(client->frameBuffer);
|
||||||
|
client->frameBuffer=malloc(client->width*client->height*client->format.bitsPerPixel/8);
|
||||||
|
return client->frameBuffer?TRUE:FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
rfbClient* rfbGetClient(int* argc,char** argv,
|
||||||
|
int bitsPerSample,int samplesPerPixel,
|
||||||
|
int bytesPerPixel) {
|
||||||
|
rfbClient* client=(rfbClient*)calloc(sizeof(rfbClient),1);
|
||||||
|
client->programName = argv[0];
|
||||||
|
client->endianTest = 1;
|
||||||
|
|
||||||
|
client->format.bitsPerPixel = bytesPerPixel*8;
|
||||||
|
client->format.depth = bitsPerSample*samplesPerPixel;
|
||||||
|
client->format.bigEndian = *(char *)&client->endianTest?FALSE:TRUE;
|
||||||
|
client->format.trueColour = TRUE;
|
||||||
|
|
||||||
|
if (client->format.bitsPerPixel == 8) {
|
||||||
|
client->format.redMax = 7;
|
||||||
|
client->format.greenMax = 7;
|
||||||
|
client->format.blueMax = 3;
|
||||||
|
client->format.redShift = 0;
|
||||||
|
client->format.greenShift = 3;
|
||||||
|
client->format.blueShift = 6;
|
||||||
|
} else {
|
||||||
|
client->format.redMax = (1 << bitsPerSample) - 1;
|
||||||
|
client->format.greenMax = (1 << bitsPerSample) - 1;
|
||||||
|
client->format.blueMax = (1 << bitsPerSample) - 1;
|
||||||
|
if(!client->format.bigEndian) {
|
||||||
|
client->format.redShift = 0;
|
||||||
|
client->format.greenShift = bitsPerSample;
|
||||||
|
client->format.blueShift = bitsPerSample * 2;
|
||||||
|
} else {
|
||||||
|
if(client->format.bitsPerPixel==8*3) {
|
||||||
|
client->format.redShift = bitsPerSample*2;
|
||||||
|
client->format.greenShift = bitsPerSample*1;
|
||||||
|
client->format.blueShift = 0;
|
||||||
|
} else {
|
||||||
|
client->format.redShift = bitsPerSample*3;
|
||||||
|
client->format.greenShift = bitsPerSample*2;
|
||||||
|
client->format.blueShift = bitsPerSample;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
client->HandleCursorPos = DummyPoint;
|
||||||
|
client->SoftCursorLockArea = DummyRect;
|
||||||
|
client->SoftCursorUnlockScreen = Dummy;
|
||||||
|
client->FramebufferUpdateReceived = DummyRect;
|
||||||
|
client->GetPassword = NoPassword;
|
||||||
|
client->MallocFrameBuffer = MallocFrameBuffer;
|
||||||
|
client->Bell = Dummy;
|
||||||
|
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintRect(rfbClient* client, int x, int y, int w, int h) {
|
||||||
|
fprintf(stderr,"Received an update for %d,%d,%d,%d.\n",x,y,w,h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveFramebufferAsPGM(rfbClient* client, int x, int y, int w, int h) {
|
||||||
|
static time_t t=0,t1;
|
||||||
|
FILE* f;
|
||||||
|
int i,j;
|
||||||
|
int bpp=client->format.bitsPerPixel/8;
|
||||||
|
int row_stride=client->width*bpp;
|
||||||
|
|
||||||
|
/* save one picture only if the last is older than 2 seconds */
|
||||||
|
t1=time(0);
|
||||||
|
if(t1-t>2)
|
||||||
|
t=t1;
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* assert bpp=4 */
|
||||||
|
if(bpp!=4) {
|
||||||
|
fprintf(stderr,"bpp = %d (!=4)\n",bpp);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
f=fopen("/tmp/framebuffer.ppm","wb");
|
||||||
|
|
||||||
|
fprintf(f,"P6\n# %s\n%d %d\n255\n",client->desktopName,client->width,client->height);
|
||||||
|
for(j=0;j<client->height*row_stride;j+=row_stride)
|
||||||
|
for(i=0;i<client->width*bpp;i+=bpp) {
|
||||||
|
if(client->format.bigEndian) {
|
||||||
|
fputc(client->frameBuffer[j+i+bpp-1],f);
|
||||||
|
fputc(client->frameBuffer[j+i+bpp-2],f);
|
||||||
|
fputc(client->frameBuffer[j+i+bpp-3],f);
|
||||||
|
} else {
|
||||||
|
fputc(client->frameBuffer[j+i+bpp+0],f);
|
||||||
|
fputc(client->frameBuffer[j+i+bpp+1],f);
|
||||||
|
fputc(client->frameBuffer[j+i+bpp+2],f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
vncEncryptBytes(unsigned char *bytes, char *passwd);
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
rfbClient* client = rfbGetClient(&argc,argv,8,3,4);
|
||||||
|
const char* vncServerHost="";
|
||||||
|
int vncServerPort=5900;
|
||||||
|
|
||||||
|
char buf1[]="pass",buf2[]="pass";
|
||||||
|
vncEncryptBytes(buf1,buf2);
|
||||||
|
|
||||||
|
client->FramebufferUpdateReceived = PrintRect;
|
||||||
|
client->FramebufferUpdateReceived = SaveFramebufferAsPGM;
|
||||||
|
|
||||||
|
/* The -listen option is used to make us a daemon process which listens for
|
||||||
|
incoming connections from servers, rather than actively connecting to a
|
||||||
|
given server. The -tunnel and -via options are useful to create
|
||||||
|
connections tunneled via SSH port forwarding. We must test for the
|
||||||
|
-listen option before invoking any Xt functions - this is because we use
|
||||||
|
forking, and Xt doesn't seem to cope with forking very well. For -listen
|
||||||
|
option, when a successful incoming connection has been accepted,
|
||||||
|
listenForIncomingConnections() returns, setting the listenSpecified
|
||||||
|
flag. */
|
||||||
|
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
if (strcmp(argv[i], "-listen") == 0) {
|
||||||
|
listenForIncomingConnections(client);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
char* colon=strchr(argv[i],':');
|
||||||
|
|
||||||
|
vncServerHost=argv[i];
|
||||||
|
if(colon) {
|
||||||
|
*colon=0;
|
||||||
|
vncServerPort=atoi(colon+1);
|
||||||
|
} else
|
||||||
|
vncServerPort=0;
|
||||||
|
vncServerPort+=5900;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO:
|
||||||
|
if (strcmp(argv[i], "-tunnel") == 0 || strcmp(argv[i], "-via") == 0) {
|
||||||
|
if (!createTunnel(&argc, argv, i))
|
||||||
|
exit(1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call the main Xt initialisation function. It parses command-line options,
|
||||||
|
generating appropriate resource specs, and makes a connection to the X
|
||||||
|
display. */
|
||||||
|
|
||||||
|
/* TODO: cmdline args
|
||||||
|
toplevel = XtVaAppInitialize(&appContext, "Vncviewer",
|
||||||
|
cmdLineOptions, numCmdLineOptions,
|
||||||
|
&argc, argv, fallback_resources,
|
||||||
|
XtNborderWidth, 0, NULL);
|
||||||
|
|
||||||
|
dpy = XtDisplay(toplevel);
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Interpret resource specs and process any remaining command-line arguments
|
||||||
|
(i.e. the VNC server name). If the server name isn't specified on the
|
||||||
|
command line, getArgsAndResources() will pop up a dialog box and wait
|
||||||
|
for one to be entered. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
GetArgsAndResources(argc, argv);
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Unless we accepted an incoming connection, make a TCP connection to the
|
||||||
|
given VNC server */
|
||||||
|
|
||||||
|
if (!client->listenSpecified) {
|
||||||
|
if (!ConnectToRFBServer(client,vncServerHost, vncServerPort)) exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialise the VNC connection, including reading the password */
|
||||||
|
|
||||||
|
if (!InitialiseRFBConnection(client)) exit(1);
|
||||||
|
|
||||||
|
SetFormatAndEncodings(client);
|
||||||
|
|
||||||
|
client->width=client->si.framebufferWidth;
|
||||||
|
client->height=client->si.framebufferHeight;
|
||||||
|
client->MallocFrameBuffer(client);
|
||||||
|
SendFramebufferUpdateRequest(client,0,0,client->width,client->height,FALSE);
|
||||||
|
|
||||||
|
/* Now enter the main loop, processing VNC messages. X events will
|
||||||
|
automatically be processed whenever the VNC connection is idle. */
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (!HandleRFBServerMessage(client))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
|
||||||
|
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this software; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* zlib.c - handle zlib encoding.
|
||||||
|
*
|
||||||
|
* This file shouldn't be compiled directly. It is included multiple times by
|
||||||
|
* rfbproto.c, each time with a different definition of the macro BPP. For
|
||||||
|
* each value of BPP, this file defines a function which handles an zlib
|
||||||
|
* encoded rectangle with BPP bits per pixel.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define HandleZlibBPP CONCAT2E(HandleZlib,BPP)
|
||||||
|
#define CARDBPP CONCAT2E(uint,BPP,_t)
|
||||||
|
|
||||||
|
static Bool
|
||||||
|
HandleZlibBPP (rfbClient* client, int rx, int ry, int rw, int rh)
|
||||||
|
{
|
||||||
|
rfbZlibHeader hdr;
|
||||||
|
int remaining;
|
||||||
|
int inflateResult;
|
||||||
|
int toRead;
|
||||||
|
|
||||||
|
/* First make sure we have a large enough raw buffer to hold the
|
||||||
|
* decompressed data. In practice, with a fixed BPP, fixed frame
|
||||||
|
* buffer size and the first update containing the entire frame
|
||||||
|
* buffer, this buffer allocation should only happen once, on the
|
||||||
|
* first update.
|
||||||
|
*/
|
||||||
|
if ( raw_buffer_size < (( rw * rh ) * ( BPP / 8 ))) {
|
||||||
|
|
||||||
|
if ( raw_buffer != NULL ) {
|
||||||
|
|
||||||
|
free( raw_buffer );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
raw_buffer_size = (( rw * rh ) * ( BPP / 8 ));
|
||||||
|
raw_buffer = (char*) malloc( raw_buffer_size );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbZlibHeader))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
remaining = Swap32IfLE(hdr.nBytes);
|
||||||
|
|
||||||
|
/* Need to initialize the decompressor state. */
|
||||||
|
decompStream.next_in = ( Bytef * )client->buffer;
|
||||||
|
decompStream.avail_in = 0;
|
||||||
|
decompStream.next_out = ( Bytef * )raw_buffer;
|
||||||
|
decompStream.avail_out = raw_buffer_size;
|
||||||
|
decompStream.data_type = Z_BINARY;
|
||||||
|
|
||||||
|
/* Initialize the decompression stream structures on the first invocation. */
|
||||||
|
if ( decompStreamInited == FALSE ) {
|
||||||
|
|
||||||
|
inflateResult = inflateInit( &decompStream );
|
||||||
|
|
||||||
|
if ( inflateResult != Z_OK ) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"inflateInit returned error: %d, msg: %s\n",
|
||||||
|
inflateResult,
|
||||||
|
decompStream.msg);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
decompStreamInited = TRUE;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inflateResult = Z_OK;
|
||||||
|
|
||||||
|
/* Process buffer full of data until no more to process, or
|
||||||
|
* some type of inflater error, or Z_STREAM_END.
|
||||||
|
*/
|
||||||
|
while (( remaining > 0 ) &&
|
||||||
|
( inflateResult == Z_OK )) {
|
||||||
|
|
||||||
|
if ( remaining > BUFFER_SIZE ) {
|
||||||
|
toRead = BUFFER_SIZE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
toRead = remaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fill the buffer, obtaining data from the server. */
|
||||||
|
if (!ReadFromRFBServer(client, client->buffer,toRead))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
decompStream.next_in = ( Bytef * )client->buffer;
|
||||||
|
decompStream.avail_in = toRead;
|
||||||
|
|
||||||
|
/* Need to uncompress buffer full. */
|
||||||
|
inflateResult = inflate( &decompStream, Z_SYNC_FLUSH );
|
||||||
|
|
||||||
|
/* We never supply a dictionary for compression. */
|
||||||
|
if ( inflateResult == Z_NEED_DICT ) {
|
||||||
|
fprintf(stderr,"zlib inflate needs a dictionary!\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if ( inflateResult < 0 ) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"zlib inflate returned error: %d, msg: %s\n",
|
||||||
|
inflateResult,
|
||||||
|
decompStream.msg);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Result buffer allocated to be at least large enough. We should
|
||||||
|
* never run out of space!
|
||||||
|
*/
|
||||||
|
if (( decompStream.avail_in > 0 ) &&
|
||||||
|
( decompStream.avail_out <= 0 )) {
|
||||||
|
fprintf(stderr,"zlib inflate ran out of space!\n");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
remaining -= toRead;
|
||||||
|
|
||||||
|
} /* while ( remaining > 0 ) */
|
||||||
|
|
||||||
|
if ( inflateResult == Z_OK ) {
|
||||||
|
|
||||||
|
/* Put the uncompressed contents of the update on the screen. */
|
||||||
|
CopyRectangle(client, raw_buffer, rx, ry, rw, rh);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
fprintf(stderr,
|
||||||
|
"zlib inflate returned error: %d, msg: %s\n",
|
||||||
|
inflateResult,
|
||||||
|
decompStream.msg);
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef CARDBPP
|
@ -0,0 +1,186 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2000, 2001 Const Kaplinsky. All Rights Reserved.
|
||||||
|
* Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
|
||||||
|
* Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this software; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* vncviewer.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <rfb/rfbproto.h>
|
||||||
|
#include <rfb/keysym.h>
|
||||||
|
|
||||||
|
#define Swap16IfLE(s) \
|
||||||
|
(*(char *)&client->endianTest ? ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) : (s))
|
||||||
|
|
||||||
|
#define Swap32IfLE(l) \
|
||||||
|
(*(char *)&client->endianTest ? ((((l) & 0xff000000) >> 24) | \
|
||||||
|
(((l) & 0x00ff0000) >> 8) | \
|
||||||
|
(((l) & 0x0000ff00) << 8) | \
|
||||||
|
(((l) & 0x000000ff) << 24)) : (l))
|
||||||
|
|
||||||
|
#define FLASH_PORT_OFFSET 5400
|
||||||
|
#define LISTEN_PORT_OFFSET 5500
|
||||||
|
#define TUNNEL_PORT_OFFSET 5500
|
||||||
|
#define SERVER_PORT_OFFSET 5900
|
||||||
|
|
||||||
|
#define DEFAULT_SSH_CMD "/usr/bin/ssh"
|
||||||
|
#define DEFAULT_TUNNEL_CMD \
|
||||||
|
(DEFAULT_SSH_CMD " -f -L %L:localhost:%R %H sleep 20")
|
||||||
|
#define DEFAULT_VIA_CMD \
|
||||||
|
(DEFAULT_SSH_CMD " -f -L %L:%H:%R %G sleep 20")
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Bool shareDesktop;
|
||||||
|
Bool viewOnly;
|
||||||
|
Bool fullScreen;
|
||||||
|
Bool grabKeyboard;
|
||||||
|
Bool raiseOnBeep;
|
||||||
|
|
||||||
|
const char* encodingsString;
|
||||||
|
|
||||||
|
Bool useBGR233;
|
||||||
|
int nColours;
|
||||||
|
Bool useSharedColours;
|
||||||
|
Bool forceOwnCmap;
|
||||||
|
Bool forceTrueColour;
|
||||||
|
int requestedDepth;
|
||||||
|
|
||||||
|
Bool useShm;
|
||||||
|
|
||||||
|
int wmDecorationWidth;
|
||||||
|
int wmDecorationHeight;
|
||||||
|
|
||||||
|
Bool debug;
|
||||||
|
|
||||||
|
int popupButtonCount;
|
||||||
|
|
||||||
|
int bumpScrollTime;
|
||||||
|
int bumpScrollPixels;
|
||||||
|
|
||||||
|
int compressLevel;
|
||||||
|
int qualityLevel;
|
||||||
|
Bool enableJPEG;
|
||||||
|
Bool useRemoteCursor;
|
||||||
|
} AppData;
|
||||||
|
|
||||||
|
|
||||||
|
struct _rfbClient;
|
||||||
|
|
||||||
|
typedef Bool (*HandleCursorPosProc)(struct _rfbClient* client, int x, int y);
|
||||||
|
typedef void (*SoftCursorLockAreaProc)(struct _rfbClient* client, int x, int y, int w, int h);
|
||||||
|
typedef void (*SoftCursorUnlockScreenProc)(struct _rfbClient* client);
|
||||||
|
typedef void (*FramebufferUpdateReceivedProc)(struct _rfbClient* client, int x, int y, int w, int h);
|
||||||
|
typedef char* (*GetPasswordProc)(struct _rfbClient* client);
|
||||||
|
typedef Bool (*MallocFrameBufferProc)(struct _rfbClient* client);
|
||||||
|
typedef void (*BellProc)(struct _rfbClient* client);
|
||||||
|
|
||||||
|
typedef struct _rfbClient {
|
||||||
|
uint8_t* frameBuffer;
|
||||||
|
int width, height;
|
||||||
|
|
||||||
|
int endianTest;
|
||||||
|
|
||||||
|
AppData appData;
|
||||||
|
|
||||||
|
const char* programName;
|
||||||
|
const char* serverHost;
|
||||||
|
int serverPort;
|
||||||
|
Bool listenSpecified;
|
||||||
|
int listenPort, flashPort;
|
||||||
|
|
||||||
|
/* Note that the CoRRE encoding uses this buffer and assumes it is big enough
|
||||||
|
to hold 255 * 255 * 32 bits -> 260100 bytes. 640*480 = 307200 bytes.
|
||||||
|
Hextile also assumes it is big enough to hold 16 * 16 * 32 bits.
|
||||||
|
Tight encoding assumes BUFFER_SIZE is at least 16384 bytes. */
|
||||||
|
|
||||||
|
#define BUFFER_SIZE (640*480)
|
||||||
|
char buffer[BUFFER_SIZE];
|
||||||
|
|
||||||
|
/* rfbproto.c */
|
||||||
|
|
||||||
|
int sock;
|
||||||
|
Bool canUseCoRRE;
|
||||||
|
Bool canUseHextile;
|
||||||
|
char *desktopName;
|
||||||
|
rfbPixelFormat format;
|
||||||
|
rfbServerInitMsg si;
|
||||||
|
char *serverCutText;
|
||||||
|
Bool newServerCutText;
|
||||||
|
|
||||||
|
/* cursor.c */
|
||||||
|
uint8_t *rcSource, *rcMask;
|
||||||
|
|
||||||
|
/* hooks */
|
||||||
|
HandleCursorPosProc HandleCursorPos;
|
||||||
|
SoftCursorLockAreaProc SoftCursorLockArea;
|
||||||
|
SoftCursorUnlockScreenProc SoftCursorUnlockScreen;
|
||||||
|
FramebufferUpdateReceivedProc FramebufferUpdateReceived;
|
||||||
|
GetPasswordProc GetPassword;
|
||||||
|
MallocFrameBufferProc MallocFrameBuffer;
|
||||||
|
BellProc Bell;
|
||||||
|
} rfbClient;
|
||||||
|
|
||||||
|
/* cursor.c */
|
||||||
|
|
||||||
|
// TODO: make callback
|
||||||
|
|
||||||
|
extern Bool HandleCursorShape(rfbClient* client,int xhot, int yhot, int width, int height, uint32_t enc);
|
||||||
|
|
||||||
|
/* listen.c */
|
||||||
|
|
||||||
|
extern void listenForIncomingConnections(rfbClient* viewer);
|
||||||
|
|
||||||
|
/* rfbproto.c */
|
||||||
|
|
||||||
|
extern Bool ConnectToRFBServer(rfbClient* client,const char *hostname, int port);
|
||||||
|
extern Bool InitialiseRFBConnection(rfbClient* client);
|
||||||
|
extern Bool SetFormatAndEncodings(rfbClient* client);
|
||||||
|
extern Bool SendIncrementalFramebufferUpdateRequest(rfbClient* client);
|
||||||
|
extern Bool SendFramebufferUpdateRequest(rfbClient* client,
|
||||||
|
int x, int y, int w, int h,
|
||||||
|
Bool incremental);
|
||||||
|
extern Bool SendPointerEvent(rfbClient* client,int x, int y, int buttonMask);
|
||||||
|
extern Bool SendKeyEvent(rfbClient* client,uint32_t key, Bool down);
|
||||||
|
extern Bool SendClientCutText(rfbClient* client,char *str, int len);
|
||||||
|
extern Bool HandleRFBServerMessage(rfbClient* client);
|
||||||
|
|
||||||
|
extern void PrintPixelFormat(rfbPixelFormat *format);
|
||||||
|
|
||||||
|
/* sockets.c */
|
||||||
|
|
||||||
|
extern Bool errorMessageOnReadFailure;
|
||||||
|
|
||||||
|
extern Bool ReadFromRFBServer(rfbClient* client, char *out, unsigned int n);
|
||||||
|
extern Bool WriteExact(rfbClient* client, char *buf, int n);
|
||||||
|
extern int FindFreeTcpPort(void);
|
||||||
|
extern int ListenAtTcpPort(int port);
|
||||||
|
extern int ConnectToTcpAddr(unsigned int host, int port);
|
||||||
|
extern int AcceptTcpConnection(int listenSock);
|
||||||
|
extern Bool SetNonBlocking(int sock);
|
||||||
|
|
||||||
|
extern Bool StringToIPAddr(const char *str, unsigned int *addr);
|
||||||
|
extern Bool SameMachine(int sock);
|
||||||
|
|
Loading…
Reference in new issue