mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 13:17:41 +00:00
Moved guac -> libguac, moving towards pluggable protocols.
This commit is contained in:
@@ -1,27 +1,15 @@
|
||||
|
||||
CFLAGS=-O2 -pedantic -Wall -Werror
|
||||
LDFLAGS=-lpng -lvncclient
|
||||
CFLAGS=-O2 -pedantic -Wall -Werror -I../libguac/include
|
||||
LDFLAGS=-L../libguac -lpng -lguac
|
||||
|
||||
.PHONY: clean
|
||||
|
||||
all: guacd
|
||||
|
||||
guacd: daemon.o client.o guacio.o protocol.o vnc_client.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) daemon.o client.o protocol.o guacio.o vnc_client.o -o guacd
|
||||
guacd: daemon.o
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) daemon.o -o guacd
|
||||
|
||||
client.o: client.c client.h guacio.h
|
||||
$(CC) $(CFLAGS) -c client.c
|
||||
|
||||
vnc_client.o: vnc_client.c vnc_client.h guacio.h
|
||||
$(CC) $(CFLAGS) -c vnc_client.c
|
||||
|
||||
protocol.o: protocol.c protocol.h guacio.h
|
||||
$(CC) $(CFLAGS) -c protocol.c
|
||||
|
||||
guacio.o: guacio.c guacio.h
|
||||
$(CC) $(CFLAGS) -c guacio.c
|
||||
|
||||
daemon.o: daemon.c client.h vnc_client.h
|
||||
daemon.o: daemon.c
|
||||
$(CC) $(CFLAGS) -c daemon.c
|
||||
|
||||
clean:
|
||||
|
@@ -1,149 +0,0 @@
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "guacio.h"
|
||||
#include "protocol.h"
|
||||
#include "client.h"
|
||||
|
||||
|
||||
png_byte** guac_alloc_png_buffer(int w, int h, int bpp) {
|
||||
|
||||
png_byte** png_buffer;
|
||||
png_byte* row;
|
||||
int y;
|
||||
|
||||
/* Allocate rows for PNG */
|
||||
png_buffer = (png_byte**) malloc(h * sizeof(png_byte*));
|
||||
for (y=0; y<h; y++) {
|
||||
row = (png_byte*) malloc(sizeof(png_byte) * bpp * w);
|
||||
png_buffer[y] = row;
|
||||
}
|
||||
|
||||
return png_buffer;
|
||||
}
|
||||
|
||||
void guac_free_png_buffer(png_byte** png_buffer, int h) {
|
||||
|
||||
int y;
|
||||
|
||||
/* Free PNG data */
|
||||
for (y = 0; y<h; y++)
|
||||
free(png_buffer[y]);
|
||||
free(png_buffer);
|
||||
|
||||
}
|
||||
|
||||
guac_client* guac_get_client(int client_fd, void (*client_init)(guac_client* client, const char* hostname, int port), const char* hostname, int port) {
|
||||
|
||||
guac_client* client = malloc(sizeof(guac_client));
|
||||
|
||||
client->io = guac_open(client_fd);
|
||||
|
||||
client_init(client, hostname, port);
|
||||
guac_flush(client->io);
|
||||
|
||||
return client;
|
||||
|
||||
}
|
||||
|
||||
void guac_free_client(guac_client* client) {
|
||||
if (client->free_handler)
|
||||
client->free_handler(client);
|
||||
|
||||
guac_close(client->io);
|
||||
|
||||
free(client);
|
||||
}
|
||||
|
||||
|
||||
void guac_start_client(guac_client* client) {
|
||||
|
||||
guac_instruction instruction;
|
||||
GUACIO* io = client->io;
|
||||
int wait_result;
|
||||
|
||||
/* VNC Client Loop */
|
||||
for (;;) {
|
||||
|
||||
/* Handle server messages */
|
||||
if (client->handle_messages) {
|
||||
client->handle_messages(client);
|
||||
guac_flush(client->io);
|
||||
}
|
||||
|
||||
wait_result = guac_instructions_waiting(io);
|
||||
if (wait_result > 0) {
|
||||
|
||||
int retval;
|
||||
retval = guac_read_instruction(io, &instruction); /* 0 if no instructions finished yet, <0 if error or EOF */
|
||||
|
||||
if (retval > 0) {
|
||||
|
||||
do {
|
||||
|
||||
if (strcmp(instruction.opcode, "mouse") == 0) {
|
||||
if (client->mouse_handler)
|
||||
client->mouse_handler(
|
||||
client,
|
||||
atoi(instruction.argv[0]), /* x */
|
||||
atoi(instruction.argv[1]), /* y */
|
||||
atoi(instruction.argv[2]) /* mask */
|
||||
);
|
||||
}
|
||||
|
||||
else if (strcmp(instruction.opcode, "key") == 0) {
|
||||
if (client->key_handler)
|
||||
client->key_handler(
|
||||
client,
|
||||
atoi(instruction.argv[0]), /* keysym */
|
||||
atoi(instruction.argv[1]) /* pressed */
|
||||
);
|
||||
}
|
||||
|
||||
else if (strcmp(instruction.opcode, "clipboard") == 0) {
|
||||
if (client->clipboard_handler)
|
||||
client->clipboard_handler(
|
||||
client,
|
||||
guac_unescape_string_inplace(instruction.argv[0]) /* data */
|
||||
);
|
||||
}
|
||||
|
||||
} while ((retval = guac_read_instruction(io, &instruction)) > 0);
|
||||
|
||||
if (retval < 0)
|
||||
return;
|
||||
}
|
||||
|
||||
if (retval < 0)
|
||||
return; /* EOF or error */
|
||||
|
||||
/* Otherwise, retval == 0 implies unfinished instruction */
|
||||
|
||||
}
|
||||
else if (wait_result < 0)
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,46 +0,0 @@
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _CLIENT_H
|
||||
#define _CLIENT_H
|
||||
|
||||
#include <png.h>
|
||||
|
||||
#include "guacio.h"
|
||||
|
||||
typedef struct guac_client {
|
||||
|
||||
GUACIO* io;
|
||||
void* data;
|
||||
|
||||
void (*handle_messages)(struct guac_client* client);
|
||||
void (*mouse_handler)(struct guac_client* client, int x, int y, int button_mask);
|
||||
void (*key_handler)(struct guac_client* client, int keysym, int pressed);
|
||||
void (*clipboard_handler)(struct guac_client* client, char* copied);
|
||||
void (*free_handler)(void* client);
|
||||
|
||||
} guac_client;
|
||||
|
||||
guac_client* guac_get_client(int client_fd, void (*client_init)(guac_client* client, const char* hostname, int port), const char* hostname, int port);
|
||||
void guac_start_client(guac_client* client);
|
||||
void guac_free_client(guac_client* client);
|
||||
png_byte** guac_alloc_png_buffer(int w, int h, int bpp);
|
||||
void guac_free_png_buffer(png_byte** png_buffer, int h);
|
||||
|
||||
#endif
|
@@ -26,7 +26,6 @@
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "client.h"
|
||||
#include "vnc_client.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
|
||||
@@ -107,7 +106,7 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
fprintf(stderr, "[guacamole] spawning client\n");
|
||||
|
||||
client = guac_get_client(connected_socket_fd, vnc_guac_client_init, connect_host, connect_port);
|
||||
client = NULL; /*guac_get_client(connected_socket_fd, vnc_guac_client_init, connect_host, connect_port); */ /* STUB! */
|
||||
guac_start_client(client);
|
||||
guac_free_client(client);
|
||||
|
||||
|
@@ -1,298 +0,0 @@
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "guacio.h"
|
||||
|
||||
char __GUACIO_BAS64_CHARACTERS[64] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
||||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
||||
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
|
||||
};
|
||||
|
||||
GUACIO* guac_open(int fd) {
|
||||
|
||||
GUACIO* io = malloc(sizeof(GUACIO));
|
||||
io->ready = 0;
|
||||
io->written = 0;
|
||||
io->fd = fd;
|
||||
|
||||
/* Allocate instruction buffer */
|
||||
io->instructionbuf_size = 1024;
|
||||
io->instructionbuf = malloc(io->instructionbuf_size);
|
||||
io->instructionbuf_used_length = 0;
|
||||
|
||||
/* Set limit */
|
||||
io->transfer_limit = 0;
|
||||
|
||||
return io;
|
||||
|
||||
}
|
||||
|
||||
void guac_close(GUACIO* io) {
|
||||
guac_flush(io);
|
||||
free(io);
|
||||
}
|
||||
|
||||
|
||||
/* Write bytes, limit rate */
|
||||
ssize_t __guac_write(GUACIO* io, const char* buf, int count) {
|
||||
|
||||
struct timeval start, end;
|
||||
int retval;
|
||||
|
||||
/* Write and time how long the write takes (microseconds) */
|
||||
gettimeofday(&start, NULL);
|
||||
retval = write(io->fd, buf, count);
|
||||
gettimeofday(&end, NULL);
|
||||
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
if (io->transfer_limit > 0) {
|
||||
|
||||
suseconds_t elapsed;
|
||||
suseconds_t required_usecs;
|
||||
|
||||
/* Get elapsed time */
|
||||
elapsed = (end.tv_sec - start.tv_sec) * 1000000 + end.tv_usec - start.tv_usec;
|
||||
|
||||
/* Calculate how much time we must sleep */
|
||||
required_usecs = retval * 1000 / io->transfer_limit - elapsed; /* useconds at transfer_limit KB/s*/
|
||||
|
||||
/* Sleep as necessary */
|
||||
if (required_usecs > 0) {
|
||||
|
||||
struct timespec required_sleep;
|
||||
|
||||
required_sleep.tv_sec = required_usecs / 1000000;
|
||||
required_sleep.tv_nsec = (required_usecs % 1000000) * 1000;
|
||||
|
||||
nanosleep(&required_sleep, NULL);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
ssize_t guac_write_int(GUACIO* io, unsigned int i) {
|
||||
|
||||
char buffer[128];
|
||||
char* ptr = &(buffer[127]);
|
||||
|
||||
*ptr = 0;
|
||||
|
||||
do {
|
||||
|
||||
ptr--;
|
||||
*ptr = '0' + (i % 10);
|
||||
|
||||
i /= 10;
|
||||
|
||||
} while (i > 0 && ptr >= buffer);
|
||||
|
||||
return guac_write_string(io, ptr);
|
||||
|
||||
}
|
||||
|
||||
ssize_t guac_write_string(GUACIO* io, const char* str) {
|
||||
|
||||
char* out_buf = io->out_buf;
|
||||
|
||||
int retval;
|
||||
|
||||
for (; *str != '\0'; str++) {
|
||||
|
||||
out_buf[io->written++] = *str;
|
||||
|
||||
/* Flush when necessary, return on error */
|
||||
if (io->written > 8188 /* sizeof(out_buf) - 4 */) {
|
||||
|
||||
struct timeval start, end;
|
||||
suseconds_t elapsed;
|
||||
|
||||
gettimeofday(&start, NULL);
|
||||
retval = __guac_write(io, out_buf, io->written);
|
||||
gettimeofday(&end, NULL);
|
||||
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
/* Get elapsed time */
|
||||
elapsed = (end.tv_sec - start.tv_sec) * 1000000 + end.tv_usec - start.tv_usec;
|
||||
|
||||
io->written = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
ssize_t __guac_write_base64_triplet(GUACIO* io, int a, int b, int c) {
|
||||
|
||||
char* out_buf = io->out_buf;
|
||||
|
||||
int retval;
|
||||
|
||||
/* Byte 1 */
|
||||
out_buf[io->written++] = __GUACIO_BAS64_CHARACTERS[(a & 0xFC) >> 2]; /* [AAAAAA]AABBBB BBBBCC CCCCCC */
|
||||
|
||||
if (b >= 0) {
|
||||
out_buf[io->written++] = __GUACIO_BAS64_CHARACTERS[((a & 0x03) << 4) | ((b & 0xF0) >> 4)]; /* AAAAAA[AABBBB]BBBBCC CCCCCC */
|
||||
|
||||
if (c >= 0) {
|
||||
out_buf[io->written++] = __GUACIO_BAS64_CHARACTERS[((b & 0x0F) << 2) | ((c & 0xC0) >> 6)]; /* AAAAAA AABBBB[BBBBCC]CCCCCC */
|
||||
out_buf[io->written++] = __GUACIO_BAS64_CHARACTERS[c & 0x3F]; /* AAAAAA AABBBB BBBBCC[CCCCCC] */
|
||||
}
|
||||
else {
|
||||
out_buf[io->written++] = __GUACIO_BAS64_CHARACTERS[((b & 0x0F) << 2)]; /* AAAAAA AABBBB[BBBB--]------ */
|
||||
out_buf[io->written++] = '='; /* AAAAAA AABBBB BBBB--[------] */
|
||||
}
|
||||
}
|
||||
else {
|
||||
out_buf[io->written++] = __GUACIO_BAS64_CHARACTERS[((a & 0x03) << 4)]; /* AAAAAA[AA----]------ ------ */
|
||||
out_buf[io->written++] = '='; /* AAAAAA AA----[------]------ */
|
||||
out_buf[io->written++] = '='; /* AAAAAA AA---- ------[------] */
|
||||
}
|
||||
|
||||
/* At this point, 4 bytes have been io->written */
|
||||
|
||||
/* Flush when necessary, return on error */
|
||||
if (io->written > 8188 /* sizeof(out_buf) - 4 */) {
|
||||
retval = __guac_write(io, out_buf, io->written);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
io->written = 0;
|
||||
}
|
||||
|
||||
if (b < 0)
|
||||
return 1;
|
||||
|
||||
if (c < 0)
|
||||
return 2;
|
||||
|
||||
return 3;
|
||||
|
||||
}
|
||||
|
||||
ssize_t __guac_write_base64_byte(GUACIO* io, char buf) {
|
||||
|
||||
int* ready_buf = io->ready_buf;
|
||||
|
||||
int retval;
|
||||
|
||||
ready_buf[io->ready++] = buf & 0xFF;
|
||||
|
||||
/* Flush triplet */
|
||||
if (io->ready == 3) {
|
||||
retval = __guac_write_base64_triplet(io, ready_buf[0], ready_buf[1], ready_buf[2]);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
io->ready = 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
ssize_t guac_write_base64(GUACIO* io, const void* buf, size_t count) {
|
||||
|
||||
int retval;
|
||||
|
||||
const char* char_buf = (const char*) buf;
|
||||
const char* end = char_buf + count;
|
||||
|
||||
while (char_buf < end) {
|
||||
|
||||
retval = __guac_write_base64_byte(io, *(char_buf++));
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
return count;
|
||||
|
||||
}
|
||||
|
||||
ssize_t guac_flush(GUACIO* io) {
|
||||
|
||||
int retval;
|
||||
|
||||
/* Flush remaining bytes in buffer */
|
||||
if (io->written > 0) {
|
||||
retval = __guac_write(io, io->out_buf, io->written);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
io->written = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
ssize_t guac_flush_base64(GUACIO* io) {
|
||||
|
||||
int retval;
|
||||
|
||||
/* Flush triplet to output buffer */
|
||||
while (io->ready > 0) {
|
||||
retval = __guac_write_base64_byte(io, -1);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int guac_select(GUACIO* io, int usec_timeout) {
|
||||
|
||||
fd_set fds;
|
||||
struct timeval timeout;
|
||||
|
||||
if (usec_timeout < 0)
|
||||
return select(io->fd + 1, &fds, NULL, NULL, NULL);
|
||||
|
||||
timeout.tv_sec = usec_timeout/1000000;
|
||||
timeout.tv_usec = usec_timeout%1000000;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(io->fd, &fds);
|
||||
|
||||
return select(io->fd + 1, &fds, NULL, NULL, &timeout);
|
||||
|
||||
}
|
||||
|
@@ -1,54 +0,0 @@
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _GUACIO_H
|
||||
#define _GUACIO_H
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
typedef struct GUACIO {
|
||||
|
||||
int fd;
|
||||
|
||||
int ready;
|
||||
int ready_buf[3];
|
||||
|
||||
int written;
|
||||
char out_buf[8192];
|
||||
|
||||
int instructionbuf_size;
|
||||
int instructionbuf_used_length;
|
||||
char* instructionbuf;
|
||||
|
||||
/* Limit */
|
||||
unsigned int transfer_limit; /* KB/sec */
|
||||
|
||||
} GUACIO;
|
||||
|
||||
GUACIO* guac_open(int fd);
|
||||
ssize_t guac_write_int(GUACIO* io, unsigned int i);
|
||||
ssize_t guac_write_string(GUACIO* io, const char* str);
|
||||
ssize_t guac_write_base64(GUACIO* io, const void* buf, size_t count);
|
||||
ssize_t guac_flush_base64(GUACIO* io);
|
||||
ssize_t guac_flush(GUACIO* io);
|
||||
int guac_select(GUACIO* io, int usec_timeout);
|
||||
void guac_close(GUACIO* io);
|
||||
|
||||
#endif
|
||||
|
@@ -1,461 +0,0 @@
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <png.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "guacio.h"
|
||||
#include "protocol.h"
|
||||
|
||||
char* guac_escape_string(const char* str) {
|
||||
|
||||
char* escaped;
|
||||
char* current;
|
||||
|
||||
int i;
|
||||
int length = 0;
|
||||
|
||||
/* Determine length */
|
||||
for (i=0; str[i] != '\0'; i++) {
|
||||
switch (str[i]) {
|
||||
|
||||
case ';':
|
||||
case ',':
|
||||
case '\\':
|
||||
length += 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
length++;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate new */
|
||||
escaped = malloc(length+1);
|
||||
|
||||
current = escaped;
|
||||
for (i=0; str[i] != '\0'; i++) {
|
||||
switch (str[i]) {
|
||||
|
||||
case ';':
|
||||
*(current++) = '\\';
|
||||
*(current++) = 's';
|
||||
break;
|
||||
|
||||
case ',':
|
||||
*(current++) = '\\';
|
||||
*(current++) = 'c';
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
*(current++) = '\\';
|
||||
*(current++) = '\\';
|
||||
break;
|
||||
|
||||
default:
|
||||
*(current++) = str[i];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
*current = '\0';
|
||||
|
||||
return escaped;
|
||||
|
||||
}
|
||||
|
||||
char* guac_unescape_string_inplace(char* str) {
|
||||
|
||||
char* from;
|
||||
char* to;
|
||||
|
||||
from = to = str;
|
||||
for (;;) {
|
||||
|
||||
char c = *(from++);
|
||||
|
||||
if (c == '\\') {
|
||||
|
||||
c = *(from++);
|
||||
if (c == 's')
|
||||
*(to++) = ';';
|
||||
|
||||
else if (c == 'c')
|
||||
*(to++) = ',';
|
||||
|
||||
else if (c == '\\')
|
||||
*(to++) = '\\';
|
||||
|
||||
else if (c == '\0') {
|
||||
*(to++) = '\\';
|
||||
break;
|
||||
}
|
||||
|
||||
else {
|
||||
*(to++) = '\\';
|
||||
*(to++) = c;
|
||||
}
|
||||
}
|
||||
|
||||
else if (c == '\0')
|
||||
break;
|
||||
|
||||
else
|
||||
*(to++) = c;
|
||||
|
||||
}
|
||||
|
||||
*to = '\0';
|
||||
|
||||
return str;
|
||||
|
||||
}
|
||||
|
||||
void guac_send_name(GUACIO* io, const char* name) {
|
||||
|
||||
char* escaped = guac_escape_string(name);
|
||||
|
||||
guac_write_string(io, "name:");
|
||||
guac_write_string(io, escaped);
|
||||
guac_write_string(io, ";");
|
||||
|
||||
free(escaped);
|
||||
|
||||
}
|
||||
|
||||
void guac_send_size(GUACIO* io, int w, int h) {
|
||||
guac_write_string(io, "size:");
|
||||
guac_write_int(io, w);
|
||||
guac_write_string(io, ",");
|
||||
guac_write_int(io, h);
|
||||
guac_write_string(io, ";");
|
||||
}
|
||||
|
||||
void guac_send_clipboard(GUACIO* io, const char* data) {
|
||||
|
||||
char* escaped = guac_escape_string(data);
|
||||
|
||||
guac_write_string(io, "clipboard:");
|
||||
guac_write_string(io, escaped);
|
||||
guac_write_string(io, ";");
|
||||
|
||||
free(escaped);
|
||||
|
||||
}
|
||||
|
||||
void guac_send_error(GUACIO* io, const char* error) {
|
||||
|
||||
char* escaped = guac_escape_string(error);
|
||||
|
||||
guac_write_string(io, "error:");
|
||||
guac_write_string(io, escaped);
|
||||
guac_write_string(io, ";");
|
||||
|
||||
free(escaped);
|
||||
|
||||
}
|
||||
|
||||
void guac_send_copy(GUACIO* io, int srcx, int srcy, int w, int h, int dstx, int dsty) {
|
||||
guac_write_string(io, "copy:");
|
||||
guac_write_int(io, srcx);
|
||||
guac_write_string(io, ",");
|
||||
guac_write_int(io, srcy);
|
||||
guac_write_string(io, ",");
|
||||
guac_write_int(io, w);
|
||||
guac_write_string(io, ",");
|
||||
guac_write_int(io, h);
|
||||
guac_write_string(io, ",");
|
||||
guac_write_int(io, dstx);
|
||||
guac_write_string(io, ",");
|
||||
guac_write_int(io, dsty);
|
||||
guac_write_string(io, ";");
|
||||
}
|
||||
|
||||
void __guac_write_png(png_structp png, png_bytep data, png_size_t length) {
|
||||
|
||||
if (guac_write_base64((GUACIO*) png->io_ptr, data, length) < 0) {
|
||||
perror("Error writing PNG");
|
||||
png_error(png, "Error writing PNG");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void __guac_write_flush(png_structp png) {
|
||||
}
|
||||
|
||||
void guac_send_png(GUACIO* io, int x, int y, png_byte** png_rows, int w, int h) {
|
||||
|
||||
png_structp png;
|
||||
png_infop png_info;
|
||||
|
||||
/* Write image */
|
||||
|
||||
/* Set up PNG writer */
|
||||
png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if (!png) {
|
||||
perror("Error initializing libpng write structure");
|
||||
return;
|
||||
}
|
||||
|
||||
png_info = png_create_info_struct(png);
|
||||
if (!png_info) {
|
||||
perror("Error initializing libpng info structure");
|
||||
png_destroy_write_struct(&png, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set error handler */
|
||||
if (setjmp(png_jmpbuf(png))) {
|
||||
perror("Error setting handler");
|
||||
png_destroy_write_struct(&png, &png_info);
|
||||
return;
|
||||
}
|
||||
|
||||
png_set_write_fn(png, io, __guac_write_png, __guac_write_flush);
|
||||
|
||||
/* Set PNG IHDR */
|
||||
png_set_IHDR(
|
||||
png,
|
||||
png_info,
|
||||
w,
|
||||
h,
|
||||
8,
|
||||
PNG_COLOR_TYPE_RGB,
|
||||
PNG_INTERLACE_NONE,
|
||||
PNG_COMPRESSION_TYPE_DEFAULT,
|
||||
PNG_FILTER_TYPE_DEFAULT
|
||||
);
|
||||
|
||||
guac_write_string(io, "png:");
|
||||
guac_write_int(io, x);
|
||||
guac_write_string(io, ",");
|
||||
guac_write_int(io, y);
|
||||
guac_write_string(io, ",");
|
||||
png_set_rows(png, png_info, png_rows);
|
||||
png_write_png(png, png_info, PNG_TRANSFORM_IDENTITY, NULL);
|
||||
|
||||
if (guac_flush_base64(io) < 0) {
|
||||
perror("Error flushing PNG");
|
||||
png_error(png, "Error flushing PNG");
|
||||
return;
|
||||
}
|
||||
|
||||
png_destroy_write_struct(&png, &png_info);
|
||||
|
||||
guac_write_string(io, ";");
|
||||
|
||||
}
|
||||
|
||||
|
||||
void guac_send_cursor(GUACIO* io, int x, int y, png_byte** png_rows, int w, int h) {
|
||||
|
||||
png_structp png;
|
||||
png_infop png_info;
|
||||
|
||||
/* Write image */
|
||||
|
||||
/* Set up PNG writer */
|
||||
png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
if (!png) {
|
||||
perror("Error initializing libpng write structure");
|
||||
return;
|
||||
}
|
||||
|
||||
png_info = png_create_info_struct(png);
|
||||
if (!png_info) {
|
||||
perror("Error initializing libpng info structure");
|
||||
png_destroy_write_struct(&png, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set error handler */
|
||||
if (setjmp(png_jmpbuf(png))) {
|
||||
perror("Error setting handler");
|
||||
png_destroy_write_struct(&png, &png_info);
|
||||
return;
|
||||
}
|
||||
|
||||
png_set_write_fn(png, io, __guac_write_png, __guac_write_flush);
|
||||
|
||||
/* Set PNG IHDR */
|
||||
png_set_IHDR(
|
||||
png,
|
||||
png_info,
|
||||
w,
|
||||
h,
|
||||
8,
|
||||
PNG_COLOR_TYPE_RGBA,
|
||||
PNG_INTERLACE_NONE,
|
||||
PNG_COMPRESSION_TYPE_DEFAULT,
|
||||
PNG_FILTER_TYPE_DEFAULT
|
||||
);
|
||||
|
||||
guac_write_string(io, "cursor:");
|
||||
guac_write_int(io, x);
|
||||
guac_write_string(io, ",");
|
||||
guac_write_int(io, y);
|
||||
guac_write_string(io, ",");
|
||||
png_set_rows(png, png_info, png_rows);
|
||||
png_write_png(png, png_info, PNG_TRANSFORM_IDENTITY, NULL);
|
||||
|
||||
if (guac_flush_base64(io) < 0) {
|
||||
perror("Error flushing PNG");
|
||||
png_error(png, "Error flushing PNG");
|
||||
return;
|
||||
}
|
||||
|
||||
png_destroy_write_struct(&png, &png_info);
|
||||
|
||||
guac_write_string(io, ";");
|
||||
|
||||
}
|
||||
|
||||
|
||||
int __guac_fill_instructionbuf(GUACIO* io) {
|
||||
|
||||
int retval;
|
||||
|
||||
/* Attempt to fill buffer */
|
||||
retval = recv(
|
||||
io->fd,
|
||||
io->instructionbuf + io->instructionbuf_used_length,
|
||||
io->instructionbuf_size - io->instructionbuf_used_length,
|
||||
0
|
||||
);
|
||||
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
io->instructionbuf_used_length += retval;
|
||||
|
||||
/* Expand buffer if necessary */
|
||||
if (io->instructionbuf_used_length > io->instructionbuf_size / 2) {
|
||||
io->instructionbuf_size *= 2;
|
||||
io->instructionbuf = realloc(io->instructionbuf, io->instructionbuf_size);
|
||||
}
|
||||
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
/* Returns new instruction if one exists, or NULL if no more instructions. */
|
||||
int guac_read_instruction(GUACIO* io, guac_instruction* parsed_instruction) {
|
||||
|
||||
int retval;
|
||||
int i = 0;
|
||||
int argcount = 0;
|
||||
int j;
|
||||
int current_arg = 0;
|
||||
|
||||
/* Loop until a instruction is read */
|
||||
for (;;) {
|
||||
|
||||
/* Search for end of instruction */
|
||||
for (; i < io->instructionbuf_used_length; i++) {
|
||||
|
||||
/* Count arguments as we look for the end */
|
||||
if (io->instructionbuf[i] == ',')
|
||||
argcount++;
|
||||
else if (io->instructionbuf[i] == ':' && argcount == 0)
|
||||
argcount++;
|
||||
|
||||
/* End found ... */
|
||||
else if (io->instructionbuf[i] == ';') {
|
||||
|
||||
/* Parse new instruction */
|
||||
char* instruction = malloc(i+1);
|
||||
memcpy(instruction, io->instructionbuf, i+1);
|
||||
instruction[i] = '\0'; /* Replace semicolon with null terminator. */
|
||||
|
||||
parsed_instruction->opcode = NULL;
|
||||
|
||||
parsed_instruction->argc = argcount;
|
||||
parsed_instruction->argv = malloc(sizeof(char*) * argcount);
|
||||
|
||||
for (j=0; j<i; j++) {
|
||||
|
||||
/* If encountered a colon, and no opcode parsed yet, set opcode and following argument */
|
||||
if (instruction[j] == ':' && parsed_instruction->opcode == NULL) {
|
||||
instruction[j] = '\0';
|
||||
parsed_instruction->argv[current_arg++] = &(instruction[j+1]);
|
||||
parsed_instruction->opcode = instruction;
|
||||
}
|
||||
|
||||
/* If encountered a comma, set following argument */
|
||||
else if (instruction[j] == ',') {
|
||||
instruction[j] = '\0';
|
||||
parsed_instruction->argv[current_arg++] = &(instruction[j+1]);
|
||||
}
|
||||
}
|
||||
|
||||
/* If no arguments, set opcode to entire instruction */
|
||||
if (parsed_instruction->opcode == NULL)
|
||||
parsed_instruction->opcode = instruction;
|
||||
|
||||
/* Found. Reset buffer */
|
||||
memmove(io->instructionbuf, io->instructionbuf + i + 1, io->instructionbuf_used_length - i - 1);
|
||||
io->instructionbuf_used_length -= i + 1;
|
||||
|
||||
/* Done */
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* No instruction yet? Get more data ... */
|
||||
retval = guac_select(io, 1000);
|
||||
if (retval <= 0)
|
||||
return retval;
|
||||
|
||||
retval = __guac_fill_instructionbuf(io);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
if (retval == 0)
|
||||
return -1; /* EOF */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void guac_free_instruction(guac_instruction* instruction) {
|
||||
free(instruction->opcode);
|
||||
|
||||
if (instruction->argv)
|
||||
free(instruction->argv);
|
||||
|
||||
free(instruction);
|
||||
}
|
||||
|
||||
|
||||
int guac_instructions_waiting(GUACIO* io) {
|
||||
|
||||
if (io->instructionbuf_used_length > 0)
|
||||
return 1;
|
||||
|
||||
return guac_select(io, 1000);
|
||||
}
|
||||
|
@@ -1,52 +0,0 @@
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __PROTOCOL_H
|
||||
#define __PROTOCOL_H
|
||||
|
||||
#include <png.h>
|
||||
|
||||
#include "guacio.h"
|
||||
|
||||
typedef struct guac_instruction {
|
||||
|
||||
char* opcode;
|
||||
|
||||
int argc;
|
||||
char** argv;
|
||||
|
||||
} guac_instruction;
|
||||
|
||||
|
||||
void guac_free_instruction(guac_instruction* instruction);
|
||||
char* guac_escape_string(const char* str);
|
||||
char* guac_unescape_string_inplace(char* str);
|
||||
void guac_send_name(GUACIO* io, const char* name);
|
||||
void guac_send_error(GUACIO* io, const char* error);
|
||||
void guac_send_clipboard(GUACIO* io, const char* data);
|
||||
void guac_send_size(GUACIO* io, int w, int h);
|
||||
void guac_send_copy(GUACIO* io, int srcx, int srcy, int w, int h, int dstx, int dsty);
|
||||
void guac_send_png(GUACIO* io, int x, int y, png_byte** png_rows, int w, int h);
|
||||
void guac_send_cursor(GUACIO* io, int x, int y, png_byte** png_rows, int w, int h);
|
||||
|
||||
int guac_instructions_waiting(GUACIO* io);
|
||||
int guac_read_instruction(GUACIO* io, guac_instruction* parsed_instruction);
|
||||
|
||||
#endif
|
||||
|
@@ -1,332 +0,0 @@
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <png.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <rfb/rfbclient.h>
|
||||
|
||||
#include "guacio.h"
|
||||
#include "protocol.h"
|
||||
#include "client.h"
|
||||
|
||||
char __guac_password[] = "potato";
|
||||
|
||||
static char* __GUAC_CLIENT = "GUAC_CLIENT";
|
||||
|
||||
typedef struct vnc_guac_client_data {
|
||||
|
||||
rfbClient* rfb_client;
|
||||
png_byte** png_buffer;
|
||||
png_byte** png_buffer_alpha;
|
||||
int copy_rect_used;
|
||||
|
||||
} vnc_guac_client_data;
|
||||
|
||||
void guac_vnc_cursor(rfbClient* client, int x, int y, int w, int h, int bpp) {
|
||||
|
||||
int dx, dy;
|
||||
|
||||
guac_client* gc = rfbClientGetClientData(client, __GUAC_CLIENT);
|
||||
GUACIO* io = gc->io;
|
||||
png_byte** png_buffer = ((vnc_guac_client_data*) gc->data)->png_buffer_alpha;
|
||||
png_byte* row;
|
||||
|
||||
png_byte** png_row_current = png_buffer;
|
||||
|
||||
unsigned int bytesPerRow = bpp * w;
|
||||
unsigned char* fb_row_current = client->rcSource;
|
||||
unsigned char* fb_mask = client->rcMask;
|
||||
unsigned char* fb_row;
|
||||
unsigned int v;
|
||||
|
||||
/* Copy image data from VNC client to PNG */
|
||||
for (dy = 0; dy<h; dy++) {
|
||||
|
||||
row = *(png_row_current++);
|
||||
|
||||
fb_row = fb_row_current;
|
||||
fb_row_current += bytesPerRow;
|
||||
|
||||
for (dx = 0; dx<w; dx++) {
|
||||
|
||||
switch (bpp) {
|
||||
case 4:
|
||||
v = *((unsigned int*) fb_row);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
v = *((unsigned short*) fb_row);
|
||||
break;
|
||||
|
||||
default:
|
||||
v = *((unsigned char*) fb_row);
|
||||
}
|
||||
|
||||
*(row++) = (v >> client->format.redShift) * 256 / (client->format.redMax+1);
|
||||
*(row++) = (v >> client->format.greenShift) * 256 / (client->format.greenMax+1);
|
||||
*(row++) = (v >> client->format.blueShift) * 256 / (client->format.blueMax+1);
|
||||
|
||||
/* Handle mask */
|
||||
if (*(fb_mask++))
|
||||
*(row++) = 255;
|
||||
else
|
||||
*(row++) = 0;
|
||||
|
||||
fb_row += bpp;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* SEND CURSOR */
|
||||
guac_send_cursor(io, x, y, png_buffer, w, h);
|
||||
|
||||
}
|
||||
void guac_vnc_update(rfbClient* client, int x, int y, int w, int h) {
|
||||
|
||||
int dx, dy;
|
||||
|
||||
guac_client* gc = rfbClientGetClientData(client, __GUAC_CLIENT);
|
||||
GUACIO* io = gc->io;
|
||||
png_byte** png_buffer = ((vnc_guac_client_data*) gc->data)->png_buffer;
|
||||
png_byte* row;
|
||||
|
||||
png_byte** png_row_current = png_buffer;
|
||||
|
||||
unsigned int bpp = client->format.bitsPerPixel/8;
|
||||
unsigned int bytesPerRow = bpp * client->width;
|
||||
unsigned char* fb_row_current = client->frameBuffer + (y * bytesPerRow) + (x * bpp);
|
||||
unsigned char* fb_row;
|
||||
unsigned int v;
|
||||
|
||||
/* Ignore extra update if already handled by copyrect */
|
||||
if (((vnc_guac_client_data*) gc->data)->copy_rect_used) {
|
||||
((vnc_guac_client_data*) gc->data)->copy_rect_used = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Copy image data from VNC client to PNG */
|
||||
for (dy = y; dy<y+h; dy++) {
|
||||
|
||||
row = *(png_row_current++);
|
||||
|
||||
fb_row = fb_row_current;
|
||||
fb_row_current += bytesPerRow;
|
||||
|
||||
for (dx = x; dx<x+w; dx++) {
|
||||
|
||||
switch (bpp) {
|
||||
case 4:
|
||||
v = *((unsigned int*) fb_row);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
v = *((unsigned short*) fb_row);
|
||||
break;
|
||||
|
||||
default:
|
||||
v = *((unsigned char*) fb_row);
|
||||
}
|
||||
|
||||
*(row++) = (v >> client->format.redShift) * 256 / (client->format.redMax+1);
|
||||
*(row++) = (v >> client->format.greenShift) * 256 / (client->format.greenMax+1);
|
||||
*(row++) = (v >> client->format.blueShift) * 256 / (client->format.blueMax+1);
|
||||
|
||||
fb_row += bpp;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
guac_send_png(io, x, y, png_buffer, w, h);
|
||||
|
||||
}
|
||||
|
||||
void guac_vnc_copyrect(rfbClient* client, int src_x, int src_y, int w, int h, int dest_x, int dest_y) {
|
||||
|
||||
guac_client* gc = rfbClientGetClientData(client, __GUAC_CLIENT);
|
||||
GUACIO* io = gc->io;
|
||||
|
||||
guac_send_copy(io, src_x, src_y, w, h, dest_x, dest_y);
|
||||
((vnc_guac_client_data*) gc->data)->copy_rect_used = 1;
|
||||
|
||||
}
|
||||
|
||||
char* guac_vnc_get_password(rfbClient* client) {
|
||||
|
||||
/* Freed after use by libvncclient */
|
||||
char* password = malloc(64);
|
||||
strncpy(password, __guac_password, 63);
|
||||
|
||||
return password;
|
||||
}
|
||||
|
||||
|
||||
void guac_vnc_cut_text(rfbClient* client, const char* text, int textlen) {
|
||||
|
||||
guac_client* gc = rfbClientGetClientData(client, __GUAC_CLIENT);
|
||||
GUACIO* io = gc->io;
|
||||
|
||||
guac_send_clipboard(io, text);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void vnc_guac_client_handle_messages(guac_client* client) {
|
||||
|
||||
int wait_result;
|
||||
rfbClient* rfb_client = ((vnc_guac_client_data*) client->data)->rfb_client;
|
||||
|
||||
|
||||
wait_result = WaitForMessage(rfb_client, 2000);
|
||||
if (wait_result < 0) {
|
||||
fprintf(stderr, "WAIT FAIL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (wait_result > 0) {
|
||||
|
||||
struct timespec sleep_period;
|
||||
|
||||
if (!HandleRFBServerMessage(rfb_client)) {
|
||||
fprintf(stderr, "HANDLE FAIL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Wait before returning ... don't want to handle
|
||||
* too many server messages. */
|
||||
|
||||
sleep_period.tv_sec = 0;
|
||||
sleep_period.tv_nsec = 50000000L /* 50 ms */;
|
||||
|
||||
nanosleep(&sleep_period, NULL);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void vnc_guac_client_mouse_handler(guac_client* client, int x, int y, int mask) {
|
||||
|
||||
rfbClient* rfb_client = ((vnc_guac_client_data*) client->data)->rfb_client;
|
||||
|
||||
SendPointerEvent(rfb_client, x, y, mask);
|
||||
|
||||
}
|
||||
|
||||
void vnc_guac_client_key_handler(guac_client* client, int keysym, int pressed) {
|
||||
|
||||
rfbClient* rfb_client = ((vnc_guac_client_data*) client->data)->rfb_client;
|
||||
|
||||
SendKeyEvent(rfb_client, keysym, pressed);
|
||||
|
||||
}
|
||||
|
||||
void vnc_guac_client_clipboard_handler(guac_client* client, char* data) {
|
||||
|
||||
rfbClient* rfb_client = ((vnc_guac_client_data*) client->data)->rfb_client;
|
||||
|
||||
SendClientCutText(rfb_client, data, strlen(data));
|
||||
|
||||
}
|
||||
|
||||
void vnc_guac_client_free_handler(guac_client* client) {
|
||||
|
||||
rfbClient* rfb_client = ((vnc_guac_client_data*) client->data)->rfb_client;
|
||||
png_byte** png_buffer = ((vnc_guac_client_data*) client->data)->png_buffer;
|
||||
png_byte** png_buffer_alpha = ((vnc_guac_client_data*) client->data)->png_buffer_alpha;
|
||||
|
||||
/* Free PNG data */
|
||||
guac_free_png_buffer(png_buffer, rfb_client->height);
|
||||
guac_free_png_buffer(png_buffer_alpha, rfb_client->height);
|
||||
|
||||
/* Clean up VNC client*/
|
||||
rfbClientCleanup(rfb_client);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void vnc_guac_client_init(guac_client* client, const char* hostname, int port) {
|
||||
|
||||
char* hostname_copy;
|
||||
|
||||
rfbClient* rfb_client;
|
||||
|
||||
png_byte** png_buffer;
|
||||
png_byte** png_buffer_alpha;
|
||||
|
||||
vnc_guac_client_data* vnc_guac_client_data;
|
||||
|
||||
/*** INIT ***/
|
||||
rfb_client = rfbGetClient(8, 3, 4); /* 32-bpp client */
|
||||
|
||||
/* Framebuffer update handler */
|
||||
rfb_client->GotFrameBufferUpdate = guac_vnc_update;
|
||||
rfb_client->GotCopyRect = guac_vnc_copyrect;
|
||||
|
||||
/* Enable client-side cursor */
|
||||
rfb_client->GotCursorShape = guac_vnc_cursor;
|
||||
rfb_client->appData.useRemoteCursor = TRUE;
|
||||
|
||||
/* Clipboard */
|
||||
rfb_client->GotXCutText = guac_vnc_cut_text;
|
||||
|
||||
/* Password */
|
||||
rfb_client->GetPassword = guac_vnc_get_password;
|
||||
|
||||
/* Connect */
|
||||
hostname_copy = malloc(1024);
|
||||
strncpy(hostname_copy, hostname, 1024);
|
||||
|
||||
rfb_client->serverHost = hostname_copy;
|
||||
rfb_client->serverPort = port;
|
||||
|
||||
rfbInitClient(rfb_client, NULL, NULL);
|
||||
|
||||
/* Allocate buffers */
|
||||
png_buffer = guac_alloc_png_buffer(rfb_client->width, rfb_client->height, 3); /* No-alpha */
|
||||
png_buffer_alpha = guac_alloc_png_buffer(rfb_client->width, rfb_client->height, 4); /* With alpha */
|
||||
|
||||
/* Store Guac data in client */
|
||||
rfbClientSetClientData(rfb_client, __GUAC_CLIENT, client);
|
||||
|
||||
/* Set client data */
|
||||
vnc_guac_client_data = malloc(sizeof(vnc_guac_client_data));
|
||||
vnc_guac_client_data->rfb_client = rfb_client;
|
||||
vnc_guac_client_data->png_buffer = png_buffer;
|
||||
vnc_guac_client_data->png_buffer_alpha = png_buffer_alpha;
|
||||
vnc_guac_client_data->copy_rect_used = 0;
|
||||
client->data = vnc_guac_client_data;
|
||||
|
||||
/* Set handlers */
|
||||
client->handle_messages = vnc_guac_client_handle_messages;
|
||||
client->mouse_handler = vnc_guac_client_mouse_handler;
|
||||
client->key_handler = vnc_guac_client_key_handler;
|
||||
client->clipboard_handler = vnc_guac_client_clipboard_handler;
|
||||
|
||||
/* Send name */
|
||||
guac_send_name(client->io, rfb_client->desktopName);
|
||||
|
||||
/* Send size */
|
||||
guac_send_size(client->io, rfb_client->width, rfb_client->height);
|
||||
|
||||
}
|
||||
|
@@ -1,28 +0,0 @@
|
||||
|
||||
/*
|
||||
* Guacamole - Clientless Remote Desktop
|
||||
* Copyright (C) 2010 Michael Jumper
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _VNC_CLIENT_H
|
||||
#define _VNC_CLIENT_H
|
||||
|
||||
#include "client.h"
|
||||
|
||||
void vnc_guac_client_init(guac_client* client, const char* hostname, int port);
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user