first alpha version of libvncclient
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