From 2f169b2b69a6ed0f8e3f53a7b6220e39b7d42b43 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Fri, 19 Oct 2012 00:19:54 -0700 Subject: [PATCH] Use handlers rather than hard file descriptor. Allow explicit alloc/free of socket. --- libguac/include/socket.h | 124 ++++++++++++++++++++++++++++++++------ libguac/src/instruction.c | 4 +- libguac/src/socket.c | 6 +- 3 files changed, 113 insertions(+), 21 deletions(-) diff --git a/libguac/include/socket.h b/libguac/include/socket.h index dbf745f1..f558f9a8 100644 --- a/libguac/include/socket.h +++ b/libguac/include/socket.h @@ -47,17 +47,71 @@ * @file socket.h */ +typedef struct guac_socket guac_socket; + +/** + * Generic read handler for socket read operations, modeled after the standard + * POSIX read() function. When set within a guac_socket, a handler of this type + * will be called when data needs to be read into the socket. + * + * @param socket The guac_socket being read from. + * @param buf The arbitrary buffer we must populate with data. + * @param count The maximum number of bytes to read into the buffer. + * @return The number of bytes read, or -1 if an error occurs. + */ +typedef ssize_t guac_socket_read_handler(guac_socket* socket, + void* buf, size_t count); + +/** + * Generic write handler for socket write operations, modeled after the standard + * POSIX write() function. When set within a guac_socket, a handler of this type + * will be called when data needs to be write into the socket. + * + * @param socket The guac_socket being written to. + * @param buf The arbitrary buffer containing data to be written. + * @param count The maximum number of bytes to write from the buffer. + * @return The number of bytes written, or -1 if an error occurs. + */ +typedef ssize_t guac_socket_write_handler(guac_socket* socket, + void* buf, size_t count); + +/** + * Generic handler for the closing of a socket, modeled after the standard + * POSIX close() function. When set within a guac_socket, a handler of this type + * will be called when the socket is closed. + * + * @param socket The guac_socket being closed. + * @return Zero on success, or -1 if an error occurs. + */ +typedef int guac_socket_free_handler(guac_socket* socket); /** * The core I/O object of Guacamole. guac_socket provides buffered input and * output as well as convenience methods for efficiently writing base64 data. */ -typedef struct guac_socket { +struct guac_socket { /** - * The file descriptor to be read from / written to. + * Arbitrary socket-specific data. */ - int fd; + void* data; + + /** + * Handler which will be called when data needs to be read from the socket. + */ + guac_socket_read_handler* read_handler; + + /** + * Handler which will be called whenever data is written to this socket. + * Note that because guac_socket automatically buffers written data, this + * handler might only get called when the socket is flushed. + */ + guac_socket_write_handler* write_handler; + + /** + * Handler which will be called when the socket is free'd (closed). + */ + guac_socket_free_handler* free_handler; /** * The number of bytes present in the base64 "ready" buffer. @@ -114,7 +168,23 @@ typedef struct guac_socket { */ char* __instructionbuf_elementv[64]; -} guac_socket; +}; + +/** + * Allocates a new, completely blank guac_socket. This guac_socket will do + * absolutely nothing when used unless its handlers are defined. + * + * @returns A newly-allocated guac_socket, or NULL if the guac_socket could + * not be allocated. + */ +guac_socket* guac_socket_alloc(); + +/** + * Frees the given guac_socket and all associated resources. + * + * @param socket The guac_socket to free. + */ +void guac_socket_free(guac_socket* socket); /** * Allocates and initializes a new guac_socket object with the given open @@ -161,11 +231,11 @@ ssize_t guac_socket_write_int(guac_socket* socket, int64_t i); ssize_t guac_socket_write_string(guac_socket* socket, const char* str); /** - * 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 + * 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 * automatically or manually. Beware that because base64 data is buffered - * 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 + * 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 * base64 data) can be made. * * If an error occurs while writing, a non-zero value is returned, and @@ -178,6 +248,35 @@ ssize_t guac_socket_write_string(guac_socket* socket, const char* str); */ ssize_t guac_socket_write_base64(guac_socket* socket, const void* buf, size_t count); +/** + * Writes the given data to the specified socket. The data written may be + * buffered until the buffer is flushed automatically or manually. + * + * If an error occurs while writing, a non-zero value is returned, and + * guac_error is set appropriately. + * + * @param socket The guac_socket object to write to. + * @param buf A buffer containing the data to write. + * @param count The number of bytes to write. + * @return Zero on success, or non-zero if an error occurs while writing. + */ +ssize_t guac_socket_write(guac_socket* socket, const void* buf, size_t count); + +/** + * Attempts to read data from the socket, filling up to the specified number + * of bytes in the given buffer. + * + * If an error occurs while writing, a non-zero value is returned, and + * guac_error is set appropriately. + * + * @param socket The guac_socket to read from. + * @param buf The buffer to read bytes into. + * @param count The maximum number of bytes to read. + * @return The number of bytes read, or non-zero if an error occurs while + * reading. + */ +ssize_t guac_socket_read(guac_socket* socket, const void* buf, size_t count); + /** * Flushes the base64 buffer, writing padding characters as necessary. * @@ -219,14 +318,5 @@ ssize_t guac_socket_flush(guac_socket* socket); */ int guac_socket_select(guac_socket* socket, int usec_timeout); -/** - * Frees resources allocated to the given guac_socket object. Note that this - * implicitly flush all buffers, but will NOT close the associated file - * descriptor. - * - * @param socket The guac_socket object to close. - */ -void guac_socket_close(guac_socket* socket); - #endif diff --git a/libguac/src/instruction.c b/libguac/src/instruction.c index 6073a69d..78724d64 100644 --- a/libguac/src/instruction.c +++ b/libguac/src/instruction.c @@ -50,8 +50,8 @@ int __guac_fill_instructionbuf(guac_socket* socket) { int retval; /* Attempt to fill buffer */ - retval = read( - socket->fd, + retval = guac_socket_read( + socket, socket->__instructionbuf + socket->__instructionbuf_used_length, socket->__instructionbuf_size - socket->__instructionbuf_used_length ); diff --git a/libguac/src/socket.c b/libguac/src/socket.c index bb35393f..cf1aa3e2 100644 --- a/libguac/src/socket.c +++ b/libguac/src/socket.c @@ -148,12 +148,14 @@ ssize_t guac_socket_write_string(guac_socket* socket, const char* str) { /* Flush when necessary, return on error */ if (socket->__written > 8188 /* sizeof(__out_buf) - 4 */) { - retval = __guac_socket_write(socket, __out_buf, socket->__written); + retval = socket->write_handler(socket, + __out_buf, socket->__written); if (retval < 0) return retval; socket->__written = 0; + } } @@ -193,7 +195,7 @@ ssize_t __guac_socket_write_base64_triplet(guac_socket* socket, int a, int b, in /* Flush when necessary, return on error */ if (socket->__written > 8188 /* sizeof(__out_buf) - 4 */) { - retval = __guac_socket_write(socket, __out_buf, socket->__written); + retval = socket->write_handler(socket, __out_buf, socket->__written); if (retval < 0) return retval;