Moved files to src/

This commit is contained in:
Michael Jumper
2010-09-21 22:39:18 +00:00
parent a8615a00a0
commit 653548be4a
7 changed files with 3 additions and 3 deletions

View File

@@ -0,0 +1,262 @@
/*
* 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 <uuid/uuid.h>
#include <syslog.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_alloc_client(GUACIO* io) {
/* Allocate new client (not handoff) */
guac_client* client = malloc(sizeof(guac_client));
memset(client, 0, sizeof(guac_client));
/* Init new client */
client->io = io;
uuid_generate(client->uuid);
return client;
}
guac_client* guac_get_client(int client_fd, guac_client_registry* registry, guac_client_init_handler* client_init, int argc, char** argv) {
guac_client* client;
GUACIO* io = guac_open(client_fd);
guac_instruction instruction;
/* Make copies of arguments */
char** safe_argv = malloc(argc * sizeof(char*));
char** scratch_argv = malloc(argc * sizeof(char*));
int i;
for (i=0; i<argc; i++)
scratch_argv[i] = safe_argv[i] = strdup(argv[i]);
/* Wait for handshaking messages */
for (;;) {
int retval;
retval = guac_read_instruction(io, &instruction); /* 0 if no instructions finished yet, <0 if error or EOF */
if (retval > 0) {
/* connect -> create new client connection */
if (strcmp(instruction.opcode, "connect") == 0) {
/* Create new client */
client = __guac_alloc_client(io);
/* Register client */
if (registry) {
guac_register_client(registry, client);
/* Send UUID to web-client */
guac_send_uuid(io, client->uuid);
guac_flush(client->io);
}
if (client_init(client, argc, scratch_argv) != 0)
return NULL;
break;
}
/* TODO: implement handoff */
}
if (retval < 0)
return NULL; /* EOF or error */
/* Otherwise, retval == 0 implies unfinished instruction */
}
/* Free memory used for arg copy */
for (i=0; i<argc; i++)
free(safe_argv[i]);
free(safe_argv);
free(scratch_argv);
return client;
}
void guac_free_client(guac_client* client, guac_client_registry* registry) {
if (client->free_handler) {
if (client->free_handler(client))
syslog(LOG_ERR, "Error calling client free handler");
}
guac_close(client->io);
guac_remove_client(registry, client->uuid);
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) {
int retval = client->handle_messages(client);
if (retval) {
syslog(LOG_ERR, "Error handling server messages");
return;
}
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)
if (
client->mouse_handler(
client,
atoi(instruction.argv[0]), /* x */
atoi(instruction.argv[1]), /* y */
atoi(instruction.argv[2]) /* mask */
)
) {
syslog(LOG_ERR, "Error handling mouse instruction");
return;
}
}
else if (strcmp(instruction.opcode, "key") == 0) {
if (client->key_handler)
if (
client->key_handler(
client,
atoi(instruction.argv[0]), /* keysym */
atoi(instruction.argv[1]) /* pressed */
)
) {
syslog(LOG_ERR, "Error handling key instruction");
return;
}
}
else if (strcmp(instruction.opcode, "clipboard") == 0) {
if (client->clipboard_handler)
if (
client->clipboard_handler(
client,
guac_unescape_string_inplace(instruction.argv[0]) /* data */
)
) {
syslog(LOG_ERR, "Error handling clipboard instruction");
return;
}
}
else if (strcmp(instruction.opcode, "disconnect") == 0) {
syslog(LOG_INFO, "Client requested disconnect");
return;
}
} while ((retval = guac_read_instruction(io, &instruction)) > 0);
if (retval < 0) {
syslog(LOG_ERR, "Error reading instruction from stream");
return;
}
}
if (retval < 0) {
syslog(LOG_ERR, "Error or end of stream");
return; /* EOF or error */
}
/* Otherwise, retval == 0 implies unfinished instruction */
}
else if (wait_result < 0) {
syslog(LOG_ERR, "Error waiting for next instruction");
return;
}
}
}

View File

@@ -0,0 +1,55 @@
/*
* 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 _CLIENTREG_H
#define _CLIENTREG_H
#include <stdlib.h>
#include <uuid/uuid.h>
#include "uuidtree.h"
#include "client.h"
guac_client_registry* guac_create_client_registry() {
guac_client_registry* registry = malloc(sizeof(guac_client_registry));
registry->root = guac_create_uuid_tree();
return registry;
}
void guac_register_client(guac_client_registry* registry, guac_client* client) {
guac_uuid_tree_put(registry->root, client->uuid, client);
}
guac_client* guac_find_client(guac_client_registry* registry, uuid_t uuid) {
return (guac_client*) guac_uuid_tree_get(registry->root, uuid);
}
void guac_remove_client(guac_client_registry* registry, uuid_t uuid) {
guac_uuid_tree_remove(registry->root, uuid);
}
void guac_cleanup_registry(guac_client_registry* registry) {
guac_cleanup_uuid_tree(registry->root);
}
#endif

View File

@@ -0,0 +1,298 @@
/*
* 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);
}

View File

@@ -0,0 +1,524 @@
/*
* 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 <uuid/uuid.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);
}
unsigned char __guac_get_base64_char_value(char c) {
if (c >= 'A' && c <= 'Z')
return c - 'A';
if (c >= 'a' && c <= 'z')
return c - 'a' + 26;
if (c >= '0' && c <= '9')
return c - '0' + 52;
if (c == '+')
return 62;
if (c == '/')
return 63;
return 0;
}
char* guac_decode_base64_inplace(char* str) {
char* from;
char* to;
from = to = str;
for (;;) {
unsigned char v1, v2, v3, v4;
char first = *(from++);
if (first == '\0')
break;
v1 = __guac_get_base64_char_value(first);
v2 = __guac_get_base64_char_value(*(from++));
v3 = __guac_get_base64_char_value(*(from++));
v4 = __guac_get_base64_char_value(*(from++));
*(to++) = (char) ((v1 << 2) | (v2 >> 4));
*(to++) = (char) ((v2 << 4) | (v3 >> 2));
*(to++) = (char) ((v3 << 6) | v4);
}
*to = '\0';
return str;
}
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_uuid(GUACIO* io, uuid_t uuid) {
guac_write_string(io, "uuid:");
guac_write_base64(io, uuid, 16);
guac_flush_base64(io);
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);
}

View File

@@ -0,0 +1,139 @@
/*
* 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 <uuid/uuid.h>
#include "uuidtree.h"
guac_uuid_tree_node* guac_create_uuid_tree() {
guac_uuid_tree_node* tree = malloc(sizeof(guac_uuid_tree_node));
tree->used = 0;
memset(tree->next, 0, sizeof(tree->next));
return tree;
}
void guac_uuid_tree_put(guac_uuid_tree_node* tree, uuid_t uuid, void* obj) {
guac_uuid_tree_node* current = tree;
int i;
unsigned char index;
for (i=0; i<sizeof(uuid_t)-1; i++) {
guac_uuid_tree_node* next;
/* Get next tree node */
index = ((unsigned char*) uuid)[i];
next = ((guac_uuid_tree_node**) current->next)[index];
/* If no node, allocate one */
if (next == NULL) {
current->used++;
next = guac_create_uuid_tree();
((guac_uuid_tree_node**) current->next)[index] = next;
}
current = next;
}
/* Store object */
index = ((unsigned char*) uuid)[i];
current->next[index] = obj;
}
void* guac_uuid_tree_get(guac_uuid_tree_node* tree, uuid_t uuid) {
guac_uuid_tree_node* current = tree;
int i;
unsigned char index;
for (i=0; i<sizeof(uuid_t)-1; i++) {
/* Get next tree node */
index = ((unsigned char*) uuid)[i];
current = ((guac_uuid_tree_node**) current->next)[index];
/* If no node, not present */
if (current == NULL)
return NULL;
}
/* Return if found */
index = ((unsigned char*) uuid)[i];
return current->next[index];
}
void guac_uuid_tree_remove(guac_uuid_tree_node* tree, uuid_t uuid) {
guac_uuid_tree_node* current = tree;
int i;
unsigned char index;
for (i=0; i<sizeof(uuid_t)-1; i++) {
/* Get next tree node */
index = ((unsigned char*) uuid)[i];
current = ((guac_uuid_tree_node**) current->next)[index];
/* If no node, nothing to remove */
if (current == NULL)
return;
}
/* Remove, if present*/
if (current->next[index]) {
current->next[index] = NULL;
current->used--;
/* FIXME: If no more objects at this node, clean up */
if (current->used == 0) {
/* STUB */
}
}
}
void guac_cleanup_uuid_tree(guac_uuid_tree_node* tree) {
int i;
for (i=0; i<sizeof(tree->next); i++) {
if (tree->next[i] != NULL) {
guac_cleanup_uuid_tree(tree->next[i]);
tree->next[i] = NULL;
}
}
free(tree);
}