Use handlers rather than hard file descriptor. Allow explicit alloc/free of socket.

This commit is contained in:
Michael Jumper 2012-10-19 00:19:54 -07:00
parent 31729bf62d
commit 2f169b2b69
3 changed files with 113 additions and 21 deletions

View File

@ -47,17 +47,71 @@
* @file socket.h * @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 * The core I/O object of Guacamole. guac_socket provides buffered input and
* output as well as convenience methods for efficiently writing base64 data. * 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. * The number of bytes present in the base64 "ready" buffer.
@ -114,7 +168,23 @@ typedef struct guac_socket {
*/ */
char* __instructionbuf_elementv[64]; 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 * 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); 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 * Writes the given binary data to the given guac_socket object as base64-
* data. The data written may be buffered until the buffer is flushed * encoded 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_socket_flush_base64() must * on top of the write buffer already used, a call to guac_socket_flush_base64()
* be made before non-base64 writes (or writes of an independent block of * must 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
@ -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); 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. * 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); 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 #endif

View File

@ -50,8 +50,8 @@ int __guac_fill_instructionbuf(guac_socket* socket) {
int retval; int retval;
/* Attempt to fill buffer */ /* Attempt to fill buffer */
retval = read( retval = guac_socket_read(
socket->fd, socket,
socket->__instructionbuf + socket->__instructionbuf_used_length, socket->__instructionbuf + socket->__instructionbuf_used_length,
socket->__instructionbuf_size - socket->__instructionbuf_used_length socket->__instructionbuf_size - socket->__instructionbuf_used_length
); );

View File

@ -148,12 +148,14 @@ ssize_t guac_socket_write_string(guac_socket* socket, const char* str) {
/* Flush when necessary, return on error */ /* Flush when necessary, return on error */
if (socket->__written > 8188 /* sizeof(__out_buf) - 4 */) { 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) if (retval < 0)
return retval; return retval;
socket->__written = 0; 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 */ /* Flush when necessary, return on error */
if (socket->__written > 8188 /* sizeof(__out_buf) - 4 */) { 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) if (retval < 0)
return retval; return retval;