Commit 0fc57f20 authored by dscho's avatar dscho

first alpha version of libvncclient

parent a1ce2ac4
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
/*
* 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
/*
* 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;
}
/*
* 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
/*
* 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;
}
}
}
}
This diff is collapsed.
/*
* 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
/*
* 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);
}
This diff is collapsed.
/*
* 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;
}
/*
* 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
/*
* 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);
......@@ -51,7 +51,7 @@
* as plaintext.
*/
unsigned char fixedkey[8] = {23,82,107,6,35,78,88,7};
static unsigned char fixedkey[8] = {23,82,107,6,35,78,88,7};
/*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment