Conversion to new naming conventions, partial logging.

This commit is contained in:
Michael Jumper 2011-11-25 12:17:20 -08:00
parent c6d1916afa
commit 682344f778
9 changed files with 455 additions and 480 deletions

View File

@ -40,11 +40,11 @@ ACLOCAL_AMFLAGS = -I m4
AM_CFLAGS = -Werror -Wall -pedantic -Iinclude AM_CFLAGS = -Werror -Wall -pedantic -Iinclude
libguacincdir = $(includedir)/guacamole libguacincdir = $(includedir)/guacamole
libguacinc_HEADERS = include/client.h include/guacio.h include/protocol.h include/client-handlers.h include/log.h include/error.h libguacinc_HEADERS = include/client.h include/socket.h include/protocol.h include/client-handlers.h include/error.h
lib_LTLIBRARIES = libguac.la lib_LTLIBRARIES = libguac.la
libguac_la_SOURCES = src/client.c src/guacio.c src/protocol.c src/client-handlers.c src/log.c src/error.c libguac_la_SOURCES = src/client.c src/socket.c src/protocol.c src/client-handlers.c src/error.c
libguac_la_LDFLAGS = -version-info 2:0:0 libguac_la_LDFLAGS = -version-info 2:0:0

View File

@ -39,7 +39,9 @@
#ifndef _GUAC_CLIENT_H #ifndef _GUAC_CLIENT_H
#define _GUAC_CLIENT_H #define _GUAC_CLIENT_H
#include "guacio.h" #include <stdarg.h>
#include "socket.h"
#include "protocol.h" #include "protocol.h"
/** /**
@ -77,6 +79,11 @@ typedef int guac_client_clipboard_handler(guac_client* client, char* copied);
*/ */
typedef int guac_client_free_handler(guac_client* client); typedef int guac_client_free_handler(guac_client* client);
/**
* Handler for logging messages
*/
typedef void guac_client_log_handler(guac_client* client, const char* format, va_list args);
/** /**
* Possible current states of the Guacamole client. Currently, the only * Possible current states of the Guacamole client. Currently, the only
* two states are RUNNING and STOPPING. * two states are RUNNING and STOPPING.
@ -106,12 +113,12 @@ typedef enum guac_client_state {
struct guac_client { struct guac_client {
/** /**
* The GUACIO structure to be used to communicate with the web-client. It is * The guac_socket structure to be used to communicate with the web-client. It is
* expected that the implementor of any Guacamole proxy client will provide * expected that the implementor of any Guacamole proxy client will provide
* their own mechanism of I/O for their protocol. The GUACIO structure is * their own mechanism of I/O for their protocol. The guac_socket structure is
* used only to communicate conveniently with the Guacamole web-client. * used only to communicate conveniently with the Guacamole web-client.
*/ */
GUACIO* io; guac_socket* io;
/** /**
* The current state of the client. When the client is first allocated, * The current state of the client. When the client is first allocated,
@ -169,7 +176,7 @@ struct guac_client {
* *
* Example: * Example:
* @code * @code
* void handle_messages(guac_client* client); * int handle_messages(guac_client* client);
* *
* int guac_client_init(guac_client* client, int argc, char** argv) { * int guac_client_init(guac_client* client, int argc, char** argv) {
* client->handle_messages = handle_messages; * client->handle_messages = handle_messages;
@ -196,7 +203,7 @@ struct guac_client {
* Example: * Example:
* @code * @code
* void mouse_handler(guac_client* client, int x, int y, int button_mask); * int mouse_handler(guac_client* client, int x, int y, int button_mask);
* *
* int guac_client_init(guac_client* client, int argc, char** argv) { * int guac_client_init(guac_client* client, int argc, char** argv) {
* client->mouse_handler = mouse_handler; * client->mouse_handler = mouse_handler;
@ -214,7 +221,7 @@ struct guac_client {
* *
* Example: * Example:
* @code * @code
* void key_handler(guac_client* client, int keysym, int pressed); * int key_handler(guac_client* client, int keysym, int pressed);
* *
* int guac_client_init(guac_client* client, int argc, char** argv) { * int guac_client_init(guac_client* client, int argc, char** argv) {
* client->key_handler = key_handler; * client->key_handler = key_handler;
@ -235,7 +242,7 @@ struct guac_client {
* *
* Example: * Example:
* @code * @code
* void clipboard_handler(guac_client* client, char* copied); * int clipboard_handler(guac_client* client, char* copied);
* *
* int guac_client_init(guac_client* client, int argc, char** argv) { * int guac_client_init(guac_client* client, int argc, char** argv) {
* client->clipboard_handler = clipboard_handler; * client->clipboard_handler = clipboard_handler;
@ -255,7 +262,7 @@ struct guac_client {
* *
* Example: * Example:
* @code * @code
* void free_handler(guac_client* client); * int free_handler(guac_client* client);
* *
* int guac_client_init(guac_client* client, int argc, char** argv) { * int guac_client_init(guac_client* client, int argc, char** argv) {
* client->free_handler = free_handler; * client->free_handler = free_handler;
@ -264,6 +271,60 @@ struct guac_client {
*/ */
guac_client_free_handler* free_handler; guac_client_free_handler* free_handler;
/**
* Handler for logging informational messages. This handler will be called
* via guac_client_log_info() when the client needs to log information.
*
* In general, only programs loading the client should implement this
* handler, as those are the programs that would provide the logging
* facilities.
*
* Client implementations should expect these handlers to already be
* set.
*
* Example:
* @code
* void log_handler(guac_client* client, const char* format, va_list args);
*
* void function_of_daemon() {
*
* guac_client* client = [client from guac_get_client()];
*
* client->log_info_handler = log_handler;
*
* }
* @endcode
*/
guac_client_log_handler* log_info_handler;
/**
* Handler for logging error messages. This handler will be called
* via guac_client_log_error() when the client needs to log an error.
*
* In general, only programs loading the client should implement this
* handler, as those are the programs that would provide the logging
* facilities.
*
* Client implementations should expect these handlers to already be
* set.
*
* Example:
* @code
* void log_handler(guac_client* client, const char* format, va_list args);
*
* void function_of_daemon() {
*
* guac_client* client = [client from guac_get_client()];
*
* client->log_error_handler = log_handler;
*
* }
* @endcode
*/
guac_client_log_handler* log_error_handler;
}; };
/** /**
@ -272,8 +333,9 @@ struct guac_client {
typedef int guac_client_init_handler(guac_client* client, int argc, char** argv); typedef int guac_client_init_handler(guac_client* client, int argc, char** argv);
/** /**
* Initialize and return a new guac_client. The pluggable client will be chosen based on * Initialize and return a new guac_client. The pluggable client will be
* the first connect message received on the given file descriptor. * chosen based on the first connect message received on the given file
* descriptor.
* *
* @param client_fd The file descriptor associated with the socket associated * @param client_fd The file descriptor associated with the socket associated
* with the connection to the web-client tunnel. * with the connection to the web-client tunnel.
@ -288,7 +350,7 @@ guac_client* guac_get_client(int client_fd, int usec_timeout);
* *
* @param client The proxy client to free all reasources of. * @param client The proxy client to free all reasources of.
*/ */
void guac_free_client(guac_client* client); void guac_client_free(guac_client* client);
/** /**
* Call the appropriate handler defined by the given client for the given * Call the appropriate handler defined by the given client for the given
@ -330,6 +392,56 @@ guac_layer* guac_client_alloc_layer(guac_client* client, int index);
*/ */
void guac_client_free_buffer(guac_client* client, guac_layer* layer); void guac_client_free_buffer(guac_client* client, guac_layer* layer);
/**
* Logs an informational message in the log used by the given client. The
* logger used will normally be defined by guacd (or whichever program loads
* the proxy client) by setting the logging handlers of the client when it is
* loaded.
*
* @param client The proxy client to log an informational message for.
* @param format A printf-style format string to log.
* @param ... Arguments to use when filling the format string for printing.
*/
void guac_client_log_info(guac_client* client, const char* format, ...);
/**
* Logs an error message in the log used by the given client. The logger
* used will normally be defined by guacd (or whichever program loads the
* proxy client) by setting the logging handlers of the client when it is
* loaded.
*
* @param client The proxy client to log an error for.
* @param format A printf-style format string to log.
* @param ... Arguments to use when filling the format string for printing.
*/
void guac_client_log_error(guac_client* client, const char* format, ...);
/**
* Logs an informational message in the log used by the given client. The
* logger used will normally be defined by guacd (or whichever program loads
* the proxy client) by setting the logging handlers of the client when it is
* loaded.
*
* @param client The proxy client to log an informational message for.
* @param format A printf-style format string to log.
* @param ap The va_list containing the arguments to be used when filling the
* format string for printing.
*/
void vguac_client_log_info(guac_client* client, const char* format, va_list ap);
/**
* Logs an error message in the log used by the given client. The logger
* used will normally be defined by guacd (or whichever program loads the
* proxy client) by setting the logging handlers of the client when it is
* loaded.
*
* @param client The proxy client to log an error for.
* @param format A printf-style format string to log.
* @param ap The va_list containing the arguments to be used when filling the
* format string for printing.
*/
void vguac_client_log_error(guac_client* client, const char* format, va_list ap);
/** /**
* The default Guacamole client layer, layer 0. * The default Guacamole client layer, layer 0.
*/ */

View File

@ -1,95 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef _GUAC_LOG_H
#define _GUAC_LOG_H
#include <stdarg.h>
/**
* Provides basic cross-platform logging facilities.
*
* @file log.h
*/
/**
* Logs an informational message in the system log, whatever
* that may be for the system being used. This will currently
* log to syslog for platforms supporting it, and stderr for
* all others.
*
* @param format A printf-style format string to log.
* @param ... Arguments to use when filling the format string for printing.
*/
void guac_log_info(const char* format, ...);
/**
* Logs an informational message in the system log, whatever
* that may be for the system being used. This will currently
* log to syslog for platforms supporting it, and stderr for
* all others.
*
* @param format A printf-style format string to log.
* @param ap The va_list containing the arguments to be used when filling the
* format string for printing.
*/
void vguac_log_info(const char* format, va_list ap);
/**
* Logs an error message in the system log, whatever
* that may be for the system being used. This will currently
* log to syslog for platforms supporting it, and stderr for
* all others.
*
* @param format A printf-style format string to log.
* @param ... Arguments to use when filling the format string for printing.
*/
void guac_log_error(const char* format, ...);
/**
* Logs an error message in the system log, whatever
* that may be for the system being used. This will currently
* log to syslog for platforms supporting it, and stderr for
* all others.
*
* @param format A printf-style format string to log.
* @param ap The va_list containing the arguments to be used when filling the
* format string for printing.
*/
void vguac_log_error(const char* format, va_list ap);
#endif

View File

@ -40,11 +40,11 @@
#include <cairo/cairo.h> #include <cairo/cairo.h>
#include "guacio.h" #include "socket.h"
/** /**
* Provides functions and structures required for communicating using the * Provides functions and structures required for communicating using the
* Guacamole protocol over a GUACIO connection, such as that provided by * Guacamole protocol over a guac_socket connection, such as that provided by
* guac_client objects. * guac_client objects.
* *
* @file protocol.h * @file protocol.h
@ -147,86 +147,86 @@ typedef struct guac_instruction {
* *
* @param instruction The instruction to free. * @param instruction The instruction to free.
*/ */
void guac_free_instruction(guac_instruction* instruction); void guac_instruction_free(guac_instruction* instruction);
/** /**
* Sends an args instruction over the given GUACIO connection. * Sends an args instruction over the given guac_socket connection.
* *
* If an error occurs sending the instruction, a non-zero value is * If an error occurs sending the instruction, a non-zero value is
* returned, and guac_error is set appropriately. * returned, and guac_error is set appropriately.
* *
* @param io The GUACIO connection to use. * @param io The guac_socket connection to use.
* @param args The NULL-terminated array of argument names (strings). * @param args The NULL-terminated array of argument names (strings).
* @return Zero on success, non-zero on error. * @return Zero on success, non-zero on error.
*/ */
int guac_send_args(GUACIO* io, const char** name); int guac_protocol_send_args(guac_socket* io, const char** name);
/** /**
* Sends a name instruction over the given GUACIO connection. * Sends a name instruction over the given guac_socket connection.
* *
* @param io The GUACIO connection to use. * @param io The guac_socket connection to use.
* @param name The name to send within the name instruction. * @param name The name to send within the name instruction.
* @return Zero on success, non-zero on error. * @return Zero on success, non-zero on error.
*/ */
int guac_send_name(GUACIO* io, const char* name); int guac_protocol_send_name(guac_socket* io, const char* name);
/** /**
* Sends a sync instruction over the given GUACIO connection. The * Sends a sync instruction over the given guac_socket connection. The
* current time in milliseconds should be passed in as the timestamp. * current time in milliseconds should be passed in as the timestamp.
* *
* If an error occurs sending the instruction, a non-zero value is * If an error occurs sending the instruction, a non-zero value is
* returned, and guac_error is set appropriately. * returned, and guac_error is set appropriately.
* *
* @param io The GUACIO connection to use. * @param io The guac_socket connection to use.
* @param timestamp The current timestamp (in milliseconds). * @param timestamp The current timestamp (in milliseconds).
* @return Zero on success, non-zero on error. * @return Zero on success, non-zero on error.
*/ */
int guac_send_sync(GUACIO* io, guac_timestamp timestamp); int guac_protocol_send_sync(guac_socket* io, guac_timestamp timestamp);
/** /**
* Sends an error instruction over the given GUACIO connection. * Sends an error instruction over the given guac_socket connection.
* *
* If an error occurs sending the instruction, a non-zero value is * If an error occurs sending the instruction, a non-zero value is
* returned, and guac_error is set appropriately. * returned, and guac_error is set appropriately.
* *
* @param io The GUACIO connection to use. * @param io The guac_socket connection to use.
* @param error The description associated with the error. * @param error The description associated with the error.
* @return Zero on success, non-zero on error. * @return Zero on success, non-zero on error.
*/ */
int guac_send_error(GUACIO* io, const char* error); int guac_protocol_send_error(guac_socket* io, const char* error);
/** /**
* Sends a clipboard instruction over the given GUACIO connection. * Sends a clipboard instruction over the given guac_socket connection.
* *
* If an error occurs sending the instruction, a non-zero value is * If an error occurs sending the instruction, a non-zero value is
* returned, and guac_error is set appropriately. * returned, and guac_error is set appropriately.
* *
* @param io The GUACIO connection to use. * @param io The guac_socket connection to use.
* @param data The clipboard data to send. * @param data The clipboard data to send.
* @return Zero on success, non-zero on error. * @return Zero on success, non-zero on error.
*/ */
int guac_send_clipboard(GUACIO* io, const char* data); int guac_protocol_send_clipboard(guac_socket* io, const char* data);
/** /**
* Sends a size instruction over the given GUACIO connection. * Sends a size instruction over the given guac_socket connection.
* *
* If an error occurs sending the instruction, a non-zero value is * If an error occurs sending the instruction, a non-zero value is
* returned, and guac_error is set appropriately. * returned, and guac_error is set appropriately.
* *
* @param io The GUACIO connection to use. * @param io The guac_socket connection to use.
* @param w The width of the display. * @param w The width of the display.
* @param h The height of the display. * @param h The height of the display.
* @return Zero on success, non-zero on error. * @return Zero on success, non-zero on error.
*/ */
int guac_send_size(GUACIO* io, int w, int h); int guac_protocol_send_size(guac_socket* io, int w, int h);
/** /**
* Sends a copy instruction over the given GUACIO connection. * Sends a copy instruction over the given guac_socket connection.
* *
* If an error occurs sending the instruction, a non-zero value is * If an error occurs sending the instruction, a non-zero value is
* returned, and guac_error is set appropriately. * returned, and guac_error is set appropriately.
* *
* @param io The GUACIO connection to use. * @param io The guac_socket connection to use.
* @param srcl The source layer. * @param srcl The source layer.
* @param srcx The X coordinate of the source rectangle. * @param srcx The X coordinate of the source rectangle.
* @param srcy The Y coordinate of the source rectangle. * @param srcy The Y coordinate of the source rectangle.
@ -240,17 +240,17 @@ int guac_send_size(GUACIO* io, int w, int h);
* should be copied. * should be copied.
* @return Zero on success, non-zero on error. * @return Zero on success, non-zero on error.
*/ */
int guac_send_copy(GUACIO* io, int guac_protocol_send_copy(guac_socket* io,
const guac_layer* srcl, int srcx, int srcy, int w, int h, const guac_layer* srcl, int srcx, int srcy, int w, int h,
guac_composite_mode mode, const guac_layer* dstl, int dstx, int dsty); guac_composite_mode mode, const guac_layer* dstl, int dstx, int dsty);
/** /**
* Sends a rect instruction over the given GUACIO connection. * Sends a rect instruction over the given guac_socket connection.
* *
* If an error occurs sending the instruction, a non-zero value is * If an error occurs sending the instruction, a non-zero value is
* returned, and guac_error is set appropriately. * returned, and guac_error is set appropriately.
* *
* @param io The GUACIO connection to use. * @param io The guac_socket connection to use.
* @param mode The composite mode to use. * @param mode The composite mode to use.
* @param layer The destination layer. * @param layer The destination layer.
* @param x The X coordinate of the rectangle. * @param x The X coordinate of the rectangle.
@ -263,18 +263,18 @@ int guac_send_copy(GUACIO* io,
* @param a The alpha (transparency) component of the color of the rectangle. * @param a The alpha (transparency) component of the color of the rectangle.
* @return Zero on success, non-zero on error. * @return Zero on success, non-zero on error.
*/ */
int guac_send_rect(GUACIO* io, int guac_protocol_send_rect(guac_socket* io,
guac_composite_mode mode, const guac_layer* layer, guac_composite_mode mode, const guac_layer* layer,
int x, int y, int width, int height, int x, int y, int width, int height,
int r, int g, int b, int a); int r, int g, int b, int a);
/** /**
* Sends a clip instruction over the given GUACIO connection. * Sends a clip instruction over the given guac_socket connection.
* *
* If an error occurs sending the instruction, a non-zero value is * If an error occurs sending the instruction, a non-zero value is
* returned, and guac_error is set appropriately. * returned, and guac_error is set appropriately.
* *
* @param io The GUACIO connection to use. * @param io The guac_socket connection to use.
* @param layer The layer to set the clipping region of. * @param layer The layer to set the clipping region of.
* @param x The X coordinate of the clipping rectangle. * @param x The X coordinate of the clipping rectangle.
* @param y The Y coordinate of the clipping rectangle. * @param y The Y coordinate of the clipping rectangle.
@ -282,17 +282,17 @@ int guac_send_rect(GUACIO* io,
* @param height The height of the clipping rectangle. * @param height The height of the clipping rectangle.
* @return Zero on success, non-zero on error. * @return Zero on success, non-zero on error.
*/ */
int guac_send_clip(GUACIO* io, const guac_layer* layer, int guac_protocol_send_clip(guac_socket* io, const guac_layer* layer,
int x, int y, int width, int height); int x, int y, int width, int height);
/** /**
* Sends a png instruction over the given GUACIO connection. The PNG image data * Sends a png instruction over the given guac_socket connection. The PNG image data
* given will be automatically base64-encoded for transmission. * given will be automatically base64-encoded for transmission.
* *
* If an error occurs sending the instruction, a non-zero value is * If an error occurs sending the instruction, a non-zero value is
* returned, and guac_error is set appropriately. * returned, and guac_error is set appropriately.
* *
* @param io The GUACIO connection to use. * @param io The guac_socket connection to use.
* @param mode The composite mode to use. * @param mode The composite mode to use.
* @param layer The destination layer. * @param layer The destination layer.
* @param x The destination X coordinate. * @param x The destination X coordinate.
@ -300,53 +300,75 @@ int guac_send_clip(GUACIO* io, const guac_layer* layer,
* @param surface A cairo surface containing the image data to send. * @param surface A cairo surface containing the image data to send.
* @return Zero on success, non-zero on error. * @return Zero on success, non-zero on error.
*/ */
int guac_send_png(GUACIO* io, guac_composite_mode mode, int guac_protocol_send_png(guac_socket* io, guac_composite_mode mode,
const guac_layer* layer, int x, int y, cairo_surface_t* surface); const guac_layer* layer, int x, int y, cairo_surface_t* surface);
/** /**
* Sends a cursor instruction over the given GUACIO connection. The PNG image * Sends a cursor instruction over the given guac_socket connection. The PNG image
* data given will be automatically base64-encoded for transmission. * data given will be automatically base64-encoded for transmission.
* *
* If an error occurs sending the instruction, a non-zero value is * If an error occurs sending the instruction, a non-zero value is
* returned, and guac_error is set appropriately. * returned, and guac_error is set appropriately.
* *
* @param io The GUACIO connection to use. * @param io The guac_socket connection to use.
* @param x The X coordinate of the cursor hotspot. * @param x The X coordinate of the cursor hotspot.
* @param y The Y coordinate of the cursor hotspot. * @param y The Y coordinate of the cursor hotspot.
* @param surface A cairo surface containing the image data to send. * @param surface A cairo surface containing the image data to send.
* @return Zero on success, non-zero on error. * @return Zero on success, non-zero on error.
*/ */
int guac_send_cursor(GUACIO* io, int x, int y, cairo_surface_t* surface); int guac_protocol_send_cursor(guac_socket* io, int x, int y, cairo_surface_t* surface);
/** /**
* Returns whether new instruction data is available on the given GUACIO * Returns whether new instruction data is available on the given guac_socket
* connection for parsing. * connection for parsing.
* *
* @param io The GUACIO connection to use. * @param io The guac_socket connection to use.
* @param usec_timeout The maximum number of microseconds to wait before * @param usec_timeout The maximum number of microseconds to wait before
* giving up. * giving up.
* @return A positive value if data is available, negative on error, or * @return A positive value if data is available, negative on error, or
* zero if no data is currently available. * zero if no data is currently available.
*/ */
int guac_instructions_waiting(GUACIO* io, int usec_timeout); int guac_protocol_instructions_waiting(guac_socket* io, int usec_timeout);
/** /**
* Reads a single instruction from the given GUACIO connection. * Reads a single instruction from the given guac_socket connection.
* *
* If an error occurs reading the instruction, NULL is returned, * If an error occurs reading the instruction, NULL is returned,
* and guac_error is set appropriately. * and guac_error is set appropriately.
* *
* @param io The GUACIO connection to use. * @param io The guac_socket connection to use.
* @param usec_timeout The maximum number of microseconds to wait before * @param usec_timeout The maximum number of microseconds to wait before
* giving up. * giving up.
* @return A new instruction if data was successfully read, NULL on * @return A new instruction if data was successfully read, NULL on
* error or if the instruction could not be read completely * error or if the instruction could not be read completely
* because the timeout elapsed, in which case guac_error will be * because the timeout elapsed, in which case guac_error will be
* set to GUAC_STATUS_INPUT_TIMEOUT and subsequent calls to * set to GUAC_STATUS_INPUT_TIMEOUT and subsequent calls to
* guac_read_instruction() will return the parsed instruction once * guac_protocol_read_instruction() will return the parsed instruction once
* enough data is available. * enough data is available.
*/ */
guac_instruction* guac_read_instruction(GUACIO* io, int usec_timeout); guac_instruction* guac_protocol_read_instruction(guac_socket* io, int usec_timeout);
/**
* Reads a single instruction with the given opcode from the given guac_socket
* connection.
*
* If an error occurs reading the instruction, NULL is returned,
* and guac_error is set appropriately.
*
* If the instruction read is not the expected instruction, NULL is returned,
* and guac_error is set to GUAC_STATUS_BAD_STATE.
*
* @param io The guac_socket connection to use.
* @param usec_timeout The maximum number of microseconds to wait before
* giving up.
* @param opcode The opcode of the instruction to read.
* @return A new instruction if an instruction with the given opcode was read,
* NULL otherwise. If an instruction was read, but the instruction had
* a different opcode, NULL is returned and guac_error is set to
* GUAC_STATUS_BAD_STATE.
*/
guac_instruction* guac_protocol_expect_instruction(guac_socket* io, int usec_timeout,
const char* opcode);
/** /**
* Returns an arbitrary timestamp. The difference between return values of any * Returns an arbitrary timestamp. The difference between return values of any
@ -356,7 +378,7 @@ guac_instruction* guac_read_instruction(GUACIO* io, int usec_timeout);
* *
* @return An arbitrary millisecond timestamp. * @return An arbitrary millisecond timestamp.
*/ */
guac_timestamp guac_current_timestamp(); guac_timestamp guac_protocol_get_timestamp();
/** /**
* Suspends execution of the current thread for the given number of * Suspends execution of the current thread for the given number of

View File

@ -35,24 +35,24 @@
* *
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
#ifndef _GUAC_GUACIO_H #ifndef _GUAC_SOCKET_H
#define _GUAC_GUACIO_H #define _GUAC_SOCKET_H
#include <stdint.h> #include <stdint.h>
#include <unistd.h> #include <unistd.h>
/** /**
* Defines the GUACIO object and functionss for using and manipulating it. * Defines the guac_socket object and functionss for using and manipulating it.
* *
* @file guacio.h * @file socket.h
*/ */
/** /**
* The core I/O object of Guacamole. GUACIO provides buffered input and output * The core I/O object of Guacamole. guac_socket provides buffered input and
* as well as convenience methods for efficiently writing base64 data. * output as well as convenience methods for efficiently writing base64 data.
*/ */
typedef struct GUACIO { typedef struct guac_socket {
/** /**
* The file descriptor to be read from / written to. * The file descriptor to be read from / written to.
@ -114,21 +114,21 @@ typedef struct GUACIO {
*/ */
char* __instructionbuf_elementv[64]; char* __instructionbuf_elementv[64];
} GUACIO; } guac_socket;
/** /**
* Allocates and initializes a new GUACIO object with the given open * Allocates and initializes a new guac_socket object with the given open
* file descriptor. * file descriptor.
* *
* If an error occurs while allocating the GUACIO object, NULL is returned, * If an error occurs while allocating the guac_socket object, NULL is returned,
* and guac_error is set appropriately. * and guac_error is set appropriately.
* *
* @param fd An open file descriptor that this GUACIO object should manage. * @param fd An open file descriptor that this guac_socket object should manage.
* @return A newly allocated GUACIO object associated with the given * @return A newly allocated guac_socket object associated with the given
* file descriptor, or NULL if an error occurs while allocating * file descriptor, or NULL if an error occurs while allocating
* the GUACIO object. * the guac_socket object.
*/ */
GUACIO* guac_open(int fd); guac_socket* guac_socket_open(int fd);
/** /**
* Parses the given string as a decimal number, returning the result as * Parses the given string as a decimal number, returning the result as
@ -142,21 +142,21 @@ GUACIO* guac_open(int fd);
int64_t guac_parse_int(const char* str); int64_t guac_parse_int(const char* str);
/** /**
* Writes the given unsigned int to the given GUACIO object. The data * Writes the given unsigned int to the given guac_socket object. The data
* written may be buffered until the buffer is flushed automatically or * written may be buffered until the buffer is flushed automatically or
* manually. * manually.
* *
* If an error occurs while writing, a non-zero value is returned, and * If an error occurs while writing, a non-zero value is returned, and
* guac_error is set appropriately. * guac_error is set appropriately.
* *
* @param io The GUACIO object to write to. * @param io The guac_socket object to write to.
* @param i The unsigned int to write. * @param i The unsigned int to write.
* @return Zero on success, or non-zero if an error occurs while writing. * @return Zero on success, or non-zero if an error occurs while writing.
*/ */
ssize_t guac_write_int(GUACIO* io, int64_t i); ssize_t guac_socket_write_int(guac_socket* io, int64_t i);
/** /**
* Writes the given string to the given GUACIO object. The data * Writes the given string to the given guac_socket object. The data
* written may be buffered until the buffer is flushed automatically or * written may be buffered until the buffer is flushed automatically or
* manually. Note that if the string can contain characters used * manually. Note that if the string can contain characters used
* internally by the Guacamole protocol (commas, semicolons, or * internally by the Guacamole protocol (commas, semicolons, or
@ -165,29 +165,29 @@ ssize_t guac_write_int(GUACIO* io, int64_t i);
* If an error occurs while writing, a non-zero value is returned, and * If an error occurs while writing, a non-zero value is returned, and
* guac_error is set appropriately. * guac_error is set appropriately.
* *
* @param io The GUACIO object to write to. * @param io The guac_socket object to write to.
* @param str The string to write. * @param str The string to write.
* @return Zero on success, or non-zero if an error occurs while writing. * @return Zero on success, or non-zero if an error occurs while writing.
*/ */
ssize_t guac_write_string(GUACIO* io, const char* str); ssize_t guac_socket_write_string(guac_socket* io, const char* str);
/** /**
* Writes the given binary data to the given GUACIO object as base64-encoded * Writes the given binary data to the given guac_socket object as base64-encoded
* data. The data written may be buffered until the buffer is flushed * data. The data written may be buffered until the buffer is flushed
* automatically or manually. Beware that because base64 data is buffered * automatically or manually. Beware that because base64 data is buffered
* on top of the write buffer already used, a call to guac_flush_base64() must * on top of the write buffer already used, a call to guac_socket_flush_base64() must
* be made before non-base64 writes (or writes of an independent block of * be made before non-base64 writes (or writes of an independent block of
* base64 data) can be made. * base64 data) can be made.
* *
* If an error occurs while writing, a non-zero value is returned, and * If an error occurs while writing, a non-zero value is returned, and
* guac_error is set appropriately. * guac_error is set appropriately.
* *
* @param io The GUACIO object to write to. * @param io The guac_socket object to write to.
* @param buf A buffer containing the data to write. * @param buf A buffer containing the data to write.
* @param count The number of bytes to write. * @param count The number of bytes to write.
* @return Zero on success, or non-zero if an error occurs while writing. * @return Zero on success, or non-zero if an error occurs while writing.
*/ */
ssize_t guac_write_base64(GUACIO* io, const void* buf, size_t count); ssize_t guac_socket_write_base64(guac_socket* io, const void* buf, size_t count);
/** /**
* Flushes the base64 buffer, writing padding characters as necessary. * Flushes the base64 buffer, writing padding characters as necessary.
@ -195,10 +195,10 @@ ssize_t guac_write_base64(GUACIO* io, const void* buf, size_t count);
* If an error occurs while writing, a non-zero value is returned, and * If an error occurs while writing, a non-zero value is returned, and
* guac_error is set appropriately. * guac_error is set appropriately.
* *
* @param io The GUACIO object to flush * @param io The guac_socket object to flush
* @return Zero on success, or non-zero if an error occurs during flush. * @return Zero on success, or non-zero if an error occurs during flush.
*/ */
ssize_t guac_flush_base64(GUACIO* io); ssize_t guac_socket_flush_base64(guac_socket* io);
/** /**
* Flushes the write buffer. * Flushes the write buffer.
@ -206,14 +206,14 @@ ssize_t guac_flush_base64(GUACIO* io);
* If an error occurs while writing, a non-zero value is returned, and * If an error occurs while writing, a non-zero value is returned, and
* guac_error is set appropriately. * guac_error is set appropriately.
* *
* @param io The GUACIO object to flush * @param io The guac_socket object to flush
* @return Zero on success, or non-zero if an error occurs during flush. * @return Zero on success, or non-zero if an error occurs during flush.
*/ */
ssize_t guac_flush(GUACIO* io); ssize_t guac_socket_flush(guac_socket* io);
/** /**
* Waits for input to be available on the given GUACIO object until the * Waits for input to be available on the given guac_socket object until the
* specified timeout elapses. * specified timeout elapses.
* *
* If an error occurs while waiting, a negative value is returned, and * If an error occurs while waiting, a negative value is returned, and
@ -222,22 +222,22 @@ ssize_t guac_flush(GUACIO* io);
* If a timeout occurs while waiting, zero value is returned, and * If a timeout occurs while waiting, zero value is returned, and
* guac_error is set to GUAC_STATUS_INPUT_TIMEOUT. * guac_error is set to GUAC_STATUS_INPUT_TIMEOUT.
* *
* @param io The GUACIO object to wait for. * @param io The guac_socket object to wait for.
* @param usec_timeout The maximum number of microseconds to wait for data, or * @param usec_timeout The maximum number of microseconds to wait for data, or
* -1 to potentially wait forever. * -1 to potentially wait forever.
* @return Positive on success, zero if the timeout elapsed and no data is * @return Positive on success, zero if the timeout elapsed and no data is
* available, negative on error. * available, negative on error.
*/ */
int guac_select(GUACIO* io, int usec_timeout); int guac_socket_select(guac_socket* io, int usec_timeout);
/** /**
* Frees resources allocated to the given GUACIO object. Note that this * Frees resources allocated to the given guac_socket object. Note that this
* implicitly flush all buffers, but will NOT close the associated file * implicitly flush all buffers, but will NOT close the associated file
* descriptor. * descriptor.
* *
* @param io The GUACIO object to close. * @param io The guac_socket object to close.
*/ */
void guac_close(GUACIO* io); void guac_socket_close(guac_socket* io);
#endif #endif

View File

@ -40,8 +40,7 @@
#include <string.h> #include <string.h>
#include <dlfcn.h> #include <dlfcn.h>
#include "log.h" #include "socket.h"
#include "guacio.h"
#include "protocol.h" #include "protocol.h"
#include "client.h" #include "client.h"
#include "client-handlers.h" #include "client-handlers.h"
@ -57,7 +56,7 @@ guac_layer __GUAC_DEFAULT_LAYER = {
const guac_layer* GUAC_DEFAULT_LAYER = &__GUAC_DEFAULT_LAYER; const guac_layer* GUAC_DEFAULT_LAYER = &__GUAC_DEFAULT_LAYER;
guac_client* __guac_alloc_client(GUACIO* io) { guac_client* __guac_alloc_client(guac_socket* io) {
/* Allocate new client (not handoff) */ /* Allocate new client (not handoff) */
guac_client* client = malloc(sizeof(guac_client)); guac_client* client = malloc(sizeof(guac_client));
@ -65,7 +64,7 @@ guac_client* __guac_alloc_client(GUACIO* io) {
/* Init new client */ /* Init new client */
client->io = io; client->io = io;
client->last_received_timestamp = client->last_sent_timestamp = guac_current_timestamp(); client->last_received_timestamp = client->last_sent_timestamp = guac_protocol_get_timestamp();
client->state = RUNNING; client->state = RUNNING;
client->__all_layers = NULL; client->__all_layers = NULL;
@ -131,7 +130,7 @@ void guac_client_free_buffer(guac_client* client, guac_layer* layer) {
guac_client* guac_get_client(int client_fd, int usec_timeout) { guac_client* guac_get_client(int client_fd, int usec_timeout) {
guac_client* client; guac_client* client;
GUACIO* io = guac_open(client_fd); guac_socket* io = guac_socket_open(client_fd);
/* Pluggable client */ /* Pluggable client */
char protocol_lib[256] = "libguac-client-"; char protocol_lib[256] = "libguac-client-";
@ -159,22 +158,22 @@ guac_client* guac_get_client(int client_fd, int usec_timeout) {
int result; int result;
/* Wait for data until timeout */ /* Wait for data until timeout */
result = guac_instructions_waiting(io, usec_timeout); result = guac_protocol_instructions_waiting(io, usec_timeout);
if (result == 0) { if (result == 0) {
guac_send_error(io, "Select timeout."); guac_protocol_send_error(io, "Select timeout.");
guac_close(io); guac_socket_close(io);
return NULL; return NULL;
} }
/* If error occurs while waiting, exit with failure */ /* If error occurs while waiting, exit with failure */
if (result < 0) { if (result < 0) {
guac_close(io); guac_socket_close(io);
return NULL; return NULL;
} }
instruction = guac_read_instruction(io, usec_timeout); instruction = guac_protocol_read_instruction(io, usec_timeout);
if (instruction == NULL) { if (instruction == NULL) {
guac_close(io); guac_socket_close(io);
return NULL; return NULL;
} }
@ -195,11 +194,11 @@ guac_client* guac_get_client(int client_fd, int usec_timeout) {
/* Load client plugin */ /* Load client plugin */
client->__client_plugin_handle = dlopen(protocol_lib, RTLD_LAZY); client->__client_plugin_handle = dlopen(protocol_lib, RTLD_LAZY);
if (!(client->__client_plugin_handle)) { if (!(client->__client_plugin_handle)) {
guac_log_error("Could not open client plugin for protocol \"%s\": %s\n", protocol, dlerror()); guac_client_log_error(client, "Could not open client plugin for protocol \"%s\": %s\n", protocol, dlerror());
guac_send_error(io, "Could not load server-side client plugin."); guac_protocol_send_error(io, "Could not load server-side client plugin.");
guac_flush(io); guac_socket_flush(io);
guac_close(io); guac_socket_close(io);
guac_free_instruction(instruction); guac_instruction_free(instruction);
return NULL; return NULL;
} }
@ -209,11 +208,11 @@ guac_client* guac_get_client(int client_fd, int usec_timeout) {
alias.obj = dlsym(client->__client_plugin_handle, "guac_client_init"); alias.obj = dlsym(client->__client_plugin_handle, "guac_client_init");
if ((error = dlerror()) != NULL) { if ((error = dlerror()) != NULL) {
guac_log_error("Could not get guac_client_init in plugin: %s\n", error); guac_client_log_error(client, "Could not get guac_client_init in plugin: %s\n", error);
guac_send_error(io, "Invalid server-side client plugin."); guac_protocol_send_error(io, "Invalid server-side client plugin.");
guac_flush(io); guac_socket_flush(io);
guac_close(io); guac_socket_close(io);
guac_free_instruction(instruction); guac_instruction_free(instruction);
return NULL; return NULL;
} }
@ -221,29 +220,29 @@ guac_client* guac_get_client(int client_fd, int usec_timeout) {
client_args = (const char**) dlsym(client->__client_plugin_handle, "GUAC_CLIENT_ARGS"); client_args = (const char**) dlsym(client->__client_plugin_handle, "GUAC_CLIENT_ARGS");
if ((error = dlerror()) != NULL) { if ((error = dlerror()) != NULL) {
guac_log_error("Could not get GUAC_CLIENT_ARGS in plugin: %s\n", error); guac_client_log_error(client, "Could not get GUAC_CLIENT_ARGS in plugin: %s\n", error);
guac_send_error(io, "Invalid server-side client plugin."); guac_protocol_send_error(io, "Invalid server-side client plugin.");
guac_flush(io); guac_socket_flush(io);
guac_close(io); guac_socket_close(io);
guac_free_instruction(instruction); guac_instruction_free(instruction);
return NULL; return NULL;
} }
if ( /* Send args */ if ( /* Send args */
guac_send_args(io, client_args) guac_protocol_send_args(io, client_args)
|| guac_flush(io) || guac_socket_flush(io)
) { ) {
guac_close(io); guac_socket_close(io);
guac_free_instruction(instruction); guac_instruction_free(instruction);
return NULL; return NULL;
} }
guac_free_instruction(instruction); guac_instruction_free(instruction);
break; break;
} /* end if select */ } /* end if select */
guac_free_instruction(instruction); guac_instruction_free(instruction);
} }
} }
@ -254,23 +253,23 @@ guac_client* guac_get_client(int client_fd, int usec_timeout) {
int result; int result;
/* Wait for data until timeout */ /* Wait for data until timeout */
result = guac_instructions_waiting(io, usec_timeout); result = guac_protocol_instructions_waiting(io, usec_timeout);
if (result == 0) { if (result == 0) {
guac_send_error(io, "Connect timeout."); guac_protocol_send_error(io, "Connect timeout.");
guac_close(io); guac_socket_close(io);
return NULL; return NULL;
} }
/* If error occurs while waiting, exit with failure */ /* If error occurs while waiting, exit with failure */
if (result < 0) { if (result < 0) {
guac_close(io); guac_socket_close(io);
return NULL; return NULL;
} }
instruction = guac_read_instruction(io, usec_timeout); instruction = guac_protocol_read_instruction(io, usec_timeout);
if (instruction == NULL) { if (instruction == NULL) {
guac_log_error("Error reading instruction while waiting for connect"); guac_client_log_error(client, "Error reading instruction while waiting for connect");
guac_close(io); guac_socket_close(io);
return NULL; return NULL;
} }
@ -285,35 +284,35 @@ guac_client* guac_get_client(int client_fd, int usec_timeout) {
if (alias.client_init(client, argc, argv) != 0) { if (alias.client_init(client, argc, argv) != 0) {
/* NOTE: On error, proxy client will send appropriate error message */ /* NOTE: On error, proxy client will send appropriate error message */
guac_free_instruction(instruction); guac_instruction_free(instruction);
guac_close(io); guac_socket_close(io);
return NULL; return NULL;
} }
guac_free_instruction(instruction); guac_instruction_free(instruction);
return client; return client;
} /* end if connect */ } /* end if connect */
guac_free_instruction(instruction); guac_instruction_free(instruction);
} }
} }
} }
void guac_free_client(guac_client* client) { void guac_client_free(guac_client* client) {
if (client->free_handler) { if (client->free_handler) {
if (client->free_handler(client)) if (client->free_handler(client))
guac_log_error("Error calling client free handler"); guac_client_log_error(client, "Error calling client free handler");
} }
guac_close(client->io); guac_socket_close(client->io);
/* Unload client plugin */ /* Unload client plugin */
if (dlclose(client->__client_plugin_handle)) { if (dlclose(client->__client_plugin_handle)) {
guac_log_error("Could not close client plugin while unloading client: %s", dlerror()); guac_client_log_error(client, "Could not close client plugin while unloading client: %s", dlerror());
} }
/* Free all layers */ /* Free all layers */

View File

@ -1,89 +0,0 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is libguac.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifdef HAVE_SYSLOG_H
#include <syslog.h>
#else
#include <stdio.h>
#endif
#include <stdarg.h>
#include "log.h"
void vguac_log_info(const char* format, va_list ap) {
#ifdef HAVE_SYSLOG_H
vsyslog(LOG_ERR, format, ap);
#else
fprintf(stderr, "guacamole: info: ");
vfprintf(stderr, format, ap);
fprintf(stderr, "\n");
#endif
}
void vguac_log_error(const char* format, va_list ap) {
#ifdef HAVE_SYSLOG_H
vsyslog(LOG_INFO, format, ap);
#else
fprintf(stderr, "guacamole: error: ");
vfprintf(stderr, format, ap);
fprintf(stderr, "\n");
#endif
}
void guac_log_info(const char* format, ...) {
va_list args;
va_start(args, format);
vguac_log_info(format, args);
va_end(args);
}
void guac_log_error(const char* format, ...) {
va_list args;
va_start(args, format);
vguac_log_error(format, args);
va_end(args);
}

View File

@ -60,181 +60,181 @@
#include <sys/socket.h> #include <sys/socket.h>
#endif #endif
#include "guacio.h" #include "socket.h"
#include "protocol.h" #include "protocol.h"
#include "error.h" #include "error.h"
ssize_t __guac_write_length_string(GUACIO* io, const char* str) { ssize_t __guac_socket_write_length_string(guac_socket* io, const char* str) {
return return
guac_write_int(io, strlen(str)) guac_socket_write_int(io, strlen(str))
|| guac_write_string(io, ".") || guac_socket_write_string(io, ".")
|| guac_write_string(io, str); || guac_socket_write_string(io, str);
} }
ssize_t __guac_write_length_int(GUACIO* io, int64_t i) { ssize_t __guac_socket_write_length_int(guac_socket* io, int64_t i) {
char buffer[128]; char buffer[128];
snprintf(buffer, sizeof(buffer), "%"PRIi64, i); snprintf(buffer, sizeof(buffer), "%"PRIi64, i);
return __guac_write_length_string(io, buffer); return __guac_socket_write_length_string(io, buffer);
} }
int guac_send_args(GUACIO* io, const char** args) { int guac_protocol_send_args(guac_socket* io, const char** args) {
int i; int i;
if (guac_write_string(io, "4.args")) return -1; if (guac_socket_write_string(io, "4.args")) return -1;
for (i=0; args[i] != NULL; i++) { for (i=0; args[i] != NULL; i++) {
if (guac_write_string(io, ",")) if (guac_socket_write_string(io, ","))
return -1; return -1;
if (__guac_write_length_string(io, args[i])) if (__guac_socket_write_length_string(io, args[i]))
return -1; return -1;
} }
return guac_write_string(io, ";"); return guac_socket_write_string(io, ";");
} }
int guac_send_name(GUACIO* io, const char* name) { int guac_protocol_send_name(guac_socket* io, const char* name) {
return return
guac_write_string(io, "4.name,") guac_socket_write_string(io, "4.name,")
|| __guac_write_length_string(io, name) || __guac_socket_write_length_string(io, name)
|| guac_write_string(io, ";"); || guac_socket_write_string(io, ";");
} }
int guac_send_size(GUACIO* io, int w, int h) { int guac_protocol_send_size(guac_socket* io, int w, int h) {
return return
guac_write_string(io, "4.size,") guac_socket_write_string(io, "4.size,")
|| __guac_write_length_int(io, w) || __guac_socket_write_length_int(io, w)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, h) || __guac_socket_write_length_int(io, h)
|| guac_write_string(io, ";"); || guac_socket_write_string(io, ";");
} }
int guac_send_clipboard(GUACIO* io, const char* data) { int guac_protocol_send_clipboard(guac_socket* io, const char* data) {
return return
guac_write_string(io, "9.clipboard,") guac_socket_write_string(io, "9.clipboard,")
|| __guac_write_length_string(io, data) || __guac_socket_write_length_string(io, data)
|| guac_write_string(io, ";"); || guac_socket_write_string(io, ";");
} }
int guac_send_error(GUACIO* io, const char* error) { int guac_protocol_send_error(guac_socket* io, const char* error) {
return return
guac_write_string(io, "5.error,") guac_socket_write_string(io, "5.error,")
|| __guac_write_length_string(io, error) || __guac_socket_write_length_string(io, error)
|| guac_write_string(io, ";"); || guac_socket_write_string(io, ";");
} }
int guac_send_sync(GUACIO* io, guac_timestamp timestamp) { int guac_protocol_send_sync(guac_socket* io, guac_timestamp timestamp) {
return return
guac_write_string(io, "4.sync,") guac_socket_write_string(io, "4.sync,")
|| __guac_write_length_int(io, timestamp) || __guac_socket_write_length_int(io, timestamp)
|| guac_write_string(io, ";"); || guac_socket_write_string(io, ";");
} }
int guac_send_copy(GUACIO* io, int guac_protocol_send_copy(guac_socket* io,
const guac_layer* srcl, int srcx, int srcy, int w, int h, const guac_layer* srcl, int srcx, int srcy, int w, int h,
guac_composite_mode mode, const guac_layer* dstl, int dstx, int dsty) { guac_composite_mode mode, const guac_layer* dstl, int dstx, int dsty) {
return return
guac_write_string(io, "4.copy,") guac_socket_write_string(io, "4.copy,")
|| __guac_write_length_int(io, srcl->index) || __guac_socket_write_length_int(io, srcl->index)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, srcx) || __guac_socket_write_length_int(io, srcx)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, srcy) || __guac_socket_write_length_int(io, srcy)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, w) || __guac_socket_write_length_int(io, w)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, h) || __guac_socket_write_length_int(io, h)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, mode) || __guac_socket_write_length_int(io, mode)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, dstl->index) || __guac_socket_write_length_int(io, dstl->index)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, dstx) || __guac_socket_write_length_int(io, dstx)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, dsty) || __guac_socket_write_length_int(io, dsty)
|| guac_write_string(io, ";"); || guac_socket_write_string(io, ";");
} }
int guac_send_rect(GUACIO* io, int guac_protocol_send_rect(guac_socket* io,
guac_composite_mode mode, const guac_layer* layer, guac_composite_mode mode, const guac_layer* layer,
int x, int y, int width, int height, int x, int y, int width, int height,
int r, int g, int b, int a) { int r, int g, int b, int a) {
return return
guac_write_string(io, "4.rect,") guac_socket_write_string(io, "4.rect,")
|| __guac_write_length_int(io, mode) || __guac_socket_write_length_int(io, mode)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, layer->index) || __guac_socket_write_length_int(io, layer->index)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, x) || __guac_socket_write_length_int(io, x)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, y) || __guac_socket_write_length_int(io, y)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, width) || __guac_socket_write_length_int(io, width)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, height) || __guac_socket_write_length_int(io, height)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, r) || __guac_socket_write_length_int(io, r)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, g) || __guac_socket_write_length_int(io, g)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, b) || __guac_socket_write_length_int(io, b)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, a) || __guac_socket_write_length_int(io, a)
|| guac_write_string(io, ";"); || guac_socket_write_string(io, ";");
} }
int guac_send_clip(GUACIO* io, const guac_layer* layer, int guac_protocol_send_clip(guac_socket* io, const guac_layer* layer,
int x, int y, int width, int height) { int x, int y, int width, int height) {
return return
guac_write_string(io, "4.clip,") guac_socket_write_string(io, "4.clip,")
|| __guac_write_length_int(io, layer->index) || __guac_socket_write_length_int(io, layer->index)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, x) || __guac_socket_write_length_int(io, x)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, y) || __guac_socket_write_length_int(io, y)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, width) || __guac_socket_write_length_int(io, width)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, height) || __guac_socket_write_length_int(io, height)
|| guac_write_string(io, ";"); || guac_socket_write_string(io, ";");
} }
typedef struct __guac_write_png_data { typedef struct __guac_socket_write_png_data {
GUACIO* io; guac_socket* io;
char* buffer; char* buffer;
int buffer_size; int buffer_size;
int data_size; int data_size;
} __guac_write_png_data; } __guac_socket_write_png_data;
cairo_status_t __guac_write_png(void* closure, const unsigned char* data, unsigned int length) { cairo_status_t __guac_socket_write_png(void* closure, const unsigned char* data, unsigned int length) {
__guac_write_png_data* png_data = (__guac_write_png_data*) closure; __guac_socket_write_png_data* png_data = (__guac_socket_write_png_data*) closure;
/* Calculate next buffer size */ /* Calculate next buffer size */
int next_size = png_data->data_size + length; int next_size = png_data->data_size + length;
@ -262,9 +262,9 @@ cairo_status_t __guac_write_png(void* closure, const unsigned char* data, unsign
} }
int __guac_write_length_png(GUACIO* io, cairo_surface_t* surface) { int __guac_socket_write_length_png(guac_socket* io, cairo_surface_t* surface) {
__guac_write_png_data png_data; __guac_socket_write_png_data png_data;
int base64_length; int base64_length;
/* Write surface */ /* Write surface */
@ -274,7 +274,7 @@ int __guac_write_length_png(GUACIO* io, cairo_surface_t* surface) {
png_data.buffer = malloc(png_data.buffer_size); png_data.buffer = malloc(png_data.buffer_size);
png_data.data_size = 0; png_data.data_size = 0;
if (cairo_surface_write_to_png_stream(surface, __guac_write_png, &png_data) != CAIRO_STATUS_SUCCESS) { if (cairo_surface_write_to_png_stream(surface, __guac_socket_write_png, &png_data) != CAIRO_STATUS_SUCCESS) {
return -1; return -1;
} }
@ -282,10 +282,10 @@ int __guac_write_length_png(GUACIO* io, cairo_surface_t* surface) {
/* Write length and data */ /* Write length and data */
if ( if (
guac_write_int(io, base64_length) guac_socket_write_int(io, base64_length)
|| guac_write_string(io, ".") || guac_socket_write_string(io, ".")
|| guac_write_base64(io, png_data.buffer, png_data.data_size) || guac_socket_write_base64(io, png_data.buffer, png_data.data_size)
|| guac_flush_base64(io)) { || guac_socket_flush_base64(io)) {
free(png_data.buffer); free(png_data.buffer);
return -1; return -1;
} }
@ -296,40 +296,40 @@ int __guac_write_length_png(GUACIO* io, cairo_surface_t* surface) {
} }
int guac_send_png(GUACIO* io, guac_composite_mode mode, int guac_protocol_send_png(guac_socket* io, guac_composite_mode mode,
const guac_layer* layer, int x, int y, cairo_surface_t* surface) { const guac_layer* layer, int x, int y, cairo_surface_t* surface) {
return return
guac_write_string(io, "3.png,") guac_socket_write_string(io, "3.png,")
|| __guac_write_length_int(io, mode) || __guac_socket_write_length_int(io, mode)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, layer->index) || __guac_socket_write_length_int(io, layer->index)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, x) || __guac_socket_write_length_int(io, x)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, y) || __guac_socket_write_length_int(io, y)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_png(io, surface) || __guac_socket_write_length_png(io, surface)
|| guac_write_string(io, ";"); || guac_socket_write_string(io, ";");
} }
int guac_send_cursor(GUACIO* io, int x, int y, cairo_surface_t* surface) { int guac_protocol_send_cursor(guac_socket* io, int x, int y, cairo_surface_t* surface) {
return return
guac_write_string(io, "6.cursor,") guac_socket_write_string(io, "6.cursor,")
|| __guac_write_length_int(io, x) || __guac_socket_write_length_int(io, x)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_int(io, y) || __guac_socket_write_length_int(io, y)
|| guac_write_string(io, ",") || guac_socket_write_string(io, ",")
|| __guac_write_length_png(io, surface) || __guac_socket_write_length_png(io, surface)
|| guac_write_string(io, ";"); || guac_socket_write_string(io, ";");
} }
int __guac_fill_instructionbuf(GUACIO* io) { int __guac_fill_instructionbuf(guac_socket* io) {
int retval; int retval;
@ -357,7 +357,7 @@ int __guac_fill_instructionbuf(GUACIO* io) {
} }
/* Returns new instruction if one exists, or NULL if no more instructions. */ /* Returns new instruction if one exists, or NULL if no more instructions. */
guac_instruction* guac_read_instruction(GUACIO* io, int usec_timeout) { guac_instruction* guac_protocol_read_instruction(guac_socket* io, int usec_timeout) {
int retval; int retval;
int i = io->__instructionbuf_parse_start; int i = io->__instructionbuf_parse_start;
@ -482,7 +482,7 @@ guac_instruction* guac_read_instruction(GUACIO* io, int usec_timeout) {
} }
/* No instruction yet? Get more data ... */ /* No instruction yet? Get more data ... */
retval = guac_select(io, usec_timeout); retval = guac_socket_select(io, usec_timeout);
if (retval <= 0) if (retval <= 0)
return NULL; return NULL;
@ -503,28 +503,54 @@ guac_instruction* guac_read_instruction(GUACIO* io, int usec_timeout) {
} }
void guac_free_instruction_data(guac_instruction* instruction) { guac_instruction* guac_protocol_expect_instruction(guac_socket* io, int usec_timeout,
const char* opcode) {
guac_instruction* instruction;
/* Wait for data until timeout */
if (guac_protocol_instructions_waiting(io, usec_timeout) <= 0)
return NULL;
/* Read available instruction */
instruction = guac_protocol_read_instruction(io, usec_timeout);
if (instruction == NULL)
return NULL;
/* Validate instruction */
if (strcmp(instruction->opcode, opcode) != 0) {
guac_error = GUAC_STATUS_BAD_STATE;
guac_instruction_free(instruction);
return NULL;
}
/* Return instruction if valid */
return instruction;
}
void guac_instruction_free_data(guac_instruction* instruction) {
free(instruction->opcode); free(instruction->opcode);
if (instruction->argv) if (instruction->argv)
free(instruction->argv); free(instruction->argv);
} }
void guac_free_instruction(guac_instruction* instruction) { void guac_instruction_free(guac_instruction* instruction) {
guac_free_instruction_data(instruction); guac_instruction_free_data(instruction);
free(instruction); free(instruction);
} }
int guac_instructions_waiting(GUACIO* io, int usec_timeout) { int guac_protocol_instructions_waiting(guac_socket* io, int usec_timeout) {
if (io->__instructionbuf_used_length > 0) if (io->__instructionbuf_used_length > 0)
return 1; return 1;
return guac_select(io, usec_timeout); return guac_socket_select(io, usec_timeout);
} }
guac_timestamp guac_current_timestamp() { guac_timestamp guac_protocol_get_timestamp() {
#ifdef HAVE_CLOCK_GETTIME #ifdef HAVE_CLOCK_GETTIME

View File

@ -52,19 +52,19 @@
#include <time.h> #include <time.h>
#include <sys/time.h> #include <sys/time.h>
#include "guacio.h" #include "socket.h"
#include "error.h" #include "error.h"
char __GUACIO_BASE64_CHARACTERS[64] = { char __guac_socket_BASE64_CHARACTERS[64] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', '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', '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', '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', '+', '/', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
}; };
GUACIO* guac_open(int fd) { guac_socket* guac_socket_open(int fd) {
GUACIO* io = malloc(sizeof(GUACIO)); guac_socket* io = malloc(sizeof(guac_socket));
/* If no memory available, return with error */ /* If no memory available, return with error */
if (io == NULL) { if (io == NULL) {
@ -96,14 +96,14 @@ GUACIO* guac_open(int fd) {
} }
void guac_close(GUACIO* io) { void guac_socket_close(guac_socket* io) {
guac_flush(io); guac_socket_flush(io);
free(io->__instructionbuf); free(io->__instructionbuf);
free(io); free(io);
} }
/* Write bytes, limit rate */ /* Write bytes, limit rate */
ssize_t __guac_write(GUACIO* io, const char* buf, int count) { ssize_t __guac_socket_write(guac_socket* io, const char* buf, int count) {
int retval; int retval;
@ -140,15 +140,15 @@ int64_t guac_parse_int(const char* str) {
} }
ssize_t guac_write_int(GUACIO* io, int64_t i) { ssize_t guac_socket_write_int(guac_socket* io, int64_t i) {
char buffer[128]; char buffer[128];
snprintf(buffer, sizeof(buffer), "%"PRIi64, i); snprintf(buffer, sizeof(buffer), "%"PRIi64, i);
return guac_write_string(io, buffer); return guac_socket_write_string(io, buffer);
} }
ssize_t guac_write_string(GUACIO* io, const char* str) { ssize_t guac_socket_write_string(guac_socket* io, const char* str) {
char* __out_buf = io->__out_buf; char* __out_buf = io->__out_buf;
@ -161,7 +161,7 @@ ssize_t guac_write_string(GUACIO* io, const char* str) {
/* Flush when necessary, return on error */ /* Flush when necessary, return on error */
if (io->__written > 8188 /* sizeof(__out_buf) - 4 */) { if (io->__written > 8188 /* sizeof(__out_buf) - 4 */) {
retval = __guac_write(io, __out_buf, io->__written); retval = __guac_socket_write(io, __out_buf, io->__written);
if (retval < 0) if (retval < 0)
return retval; return retval;
@ -175,29 +175,29 @@ ssize_t guac_write_string(GUACIO* io, const char* str) {
} }
ssize_t __guac_write_base64_triplet(GUACIO* io, int a, int b, int c) { ssize_t __guac_socket_write_base64_triplet(guac_socket* io, int a, int b, int c) {
char* __out_buf = io->__out_buf; char* __out_buf = io->__out_buf;
int retval; int retval;
/* Byte 1 */ /* Byte 1 */
__out_buf[io->__written++] = __GUACIO_BASE64_CHARACTERS[(a & 0xFC) >> 2]; /* [AAAAAA]AABBBB BBBBCC CCCCCC */ __out_buf[io->__written++] = __guac_socket_BASE64_CHARACTERS[(a & 0xFC) >> 2]; /* [AAAAAA]AABBBB BBBBCC CCCCCC */
if (b >= 0) { if (b >= 0) {
__out_buf[io->__written++] = __GUACIO_BASE64_CHARACTERS[((a & 0x03) << 4) | ((b & 0xF0) >> 4)]; /* AAAAAA[AABBBB]BBBBCC CCCCCC */ __out_buf[io->__written++] = __guac_socket_BASE64_CHARACTERS[((a & 0x03) << 4) | ((b & 0xF0) >> 4)]; /* AAAAAA[AABBBB]BBBBCC CCCCCC */
if (c >= 0) { if (c >= 0) {
__out_buf[io->__written++] = __GUACIO_BASE64_CHARACTERS[((b & 0x0F) << 2) | ((c & 0xC0) >> 6)]; /* AAAAAA AABBBB[BBBBCC]CCCCCC */ __out_buf[io->__written++] = __guac_socket_BASE64_CHARACTERS[((b & 0x0F) << 2) | ((c & 0xC0) >> 6)]; /* AAAAAA AABBBB[BBBBCC]CCCCCC */
__out_buf[io->__written++] = __GUACIO_BASE64_CHARACTERS[c & 0x3F]; /* AAAAAA AABBBB BBBBCC[CCCCCC] */ __out_buf[io->__written++] = __guac_socket_BASE64_CHARACTERS[c & 0x3F]; /* AAAAAA AABBBB BBBBCC[CCCCCC] */
} }
else { else {
__out_buf[io->__written++] = __GUACIO_BASE64_CHARACTERS[((b & 0x0F) << 2)]; /* AAAAAA AABBBB[BBBB--]------ */ __out_buf[io->__written++] = __guac_socket_BASE64_CHARACTERS[((b & 0x0F) << 2)]; /* AAAAAA AABBBB[BBBB--]------ */
__out_buf[io->__written++] = '='; /* AAAAAA AABBBB BBBB--[------] */ __out_buf[io->__written++] = '='; /* AAAAAA AABBBB BBBB--[------] */
} }
} }
else { else {
__out_buf[io->__written++] = __GUACIO_BASE64_CHARACTERS[((a & 0x03) << 4)]; /* AAAAAA[AA----]------ ------ */ __out_buf[io->__written++] = __guac_socket_BASE64_CHARACTERS[((a & 0x03) << 4)]; /* AAAAAA[AA----]------ ------ */
__out_buf[io->__written++] = '='; /* AAAAAA AA----[------]------ */ __out_buf[io->__written++] = '='; /* AAAAAA AA----[------]------ */
__out_buf[io->__written++] = '='; /* AAAAAA AA---- ------[------] */ __out_buf[io->__written++] = '='; /* AAAAAA AA---- ------[------] */
} }
@ -206,7 +206,7 @@ ssize_t __guac_write_base64_triplet(GUACIO* io, int a, int b, int c) {
/* Flush when necessary, return on error */ /* Flush when necessary, return on error */
if (io->__written > 8188 /* sizeof(__out_buf) - 4 */) { if (io->__written > 8188 /* sizeof(__out_buf) - 4 */) {
retval = __guac_write(io, __out_buf, io->__written); retval = __guac_socket_write(io, __out_buf, io->__written);
if (retval < 0) if (retval < 0)
return retval; return retval;
@ -223,7 +223,7 @@ ssize_t __guac_write_base64_triplet(GUACIO* io, int a, int b, int c) {
} }
ssize_t __guac_write_base64_byte(GUACIO* io, char buf) { ssize_t __guac_socket_write_base64_byte(guac_socket* io, char buf) {
int* __ready_buf = io->__ready_buf; int* __ready_buf = io->__ready_buf;
@ -233,7 +233,7 @@ ssize_t __guac_write_base64_byte(GUACIO* io, char buf) {
/* Flush triplet */ /* Flush triplet */
if (io->__ready == 3) { if (io->__ready == 3) {
retval = __guac_write_base64_triplet(io, __ready_buf[0], __ready_buf[1], __ready_buf[2]); retval = __guac_socket_write_base64_triplet(io, __ready_buf[0], __ready_buf[1], __ready_buf[2]);
if (retval < 0) if (retval < 0)
return retval; return retval;
@ -243,7 +243,7 @@ ssize_t __guac_write_base64_byte(GUACIO* io, char buf) {
return 1; return 1;
} }
ssize_t guac_write_base64(GUACIO* io, const void* buf, size_t count) { ssize_t guac_socket_write_base64(guac_socket* io, const void* buf, size_t count) {
int retval; int retval;
@ -252,7 +252,7 @@ ssize_t guac_write_base64(GUACIO* io, const void* buf, size_t count) {
while (char_buf < end) { while (char_buf < end) {
retval = __guac_write_base64_byte(io, *(char_buf++)); retval = __guac_socket_write_base64_byte(io, *(char_buf++));
if (retval < 0) if (retval < 0)
return retval; return retval;
@ -262,13 +262,13 @@ ssize_t guac_write_base64(GUACIO* io, const void* buf, size_t count) {
} }
ssize_t guac_flush(GUACIO* io) { ssize_t guac_socket_flush(guac_socket* io) {
int retval; int retval;
/* Flush remaining bytes in buffer */ /* Flush remaining bytes in buffer */
if (io->__written > 0) { if (io->__written > 0) {
retval = __guac_write(io, io->__out_buf, io->__written); retval = __guac_socket_write(io, io->__out_buf, io->__written);
if (retval < 0) if (retval < 0)
return retval; return retval;
@ -279,13 +279,13 @@ ssize_t guac_flush(GUACIO* io) {
} }
ssize_t guac_flush_base64(GUACIO* io) { ssize_t guac_socket_flush_base64(guac_socket* io) {
int retval; int retval;
/* Flush triplet to output buffer */ /* Flush triplet to output buffer */
while (io->__ready > 0) { while (io->__ready > 0) {
retval = __guac_write_base64_byte(io, -1); retval = __guac_socket_write_base64_byte(io, -1);
if (retval < 0) if (retval < 0)
return retval; return retval;
} }
@ -295,7 +295,7 @@ ssize_t guac_flush_base64(GUACIO* io) {
} }
int guac_select(GUACIO* io, int usec_timeout) { int guac_socket_select(guac_socket* io, int usec_timeout) {
fd_set fds; fd_set fds;
struct timeval timeout; struct timeval timeout;