From e463360aad4e48deabce584e5ba5d37760037f5c Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Fri, 11 Mar 2011 18:57:53 -0800 Subject: [PATCH] Sync message support. --- libguac/configure.in | 4 +-- libguac/include/guacio.h | 2 +- libguac/include/protocol.h | 9 ++++++ libguac/src/client.c | 66 ++++++++++++++++++++++++++++++++++---- libguac/src/guacio.c | 2 +- libguac/src/protocol.c | 8 +++++ 6 files changed, 80 insertions(+), 11 deletions(-) diff --git a/libguac/configure.in b/libguac/configure.in index 9abab0d3..9e7381a7 100644 --- a/libguac/configure.in +++ b/libguac/configure.in @@ -48,7 +48,7 @@ AC_CHECK_LIB([png], [png_write_png],, AC_MSG_ERROR("libpng is required for writi AC_CHECK_LIB([wsock32], [main]) # Checks for header files. -AC_CHECK_HEADERS([fcntl.h stdlib.h string.h sys/socket.h sys/time.h syslog.h unistd.h pngstruct.h]) +AC_CHECK_HEADERS([fcntl.h stdlib.h string.h sys/socket.h time.h sys/time.h syslog.h unistd.h pngstruct.h]) # Checks for typedefs, structures, and compiler characteristics. AC_TYPE_SIZE_T @@ -57,7 +57,7 @@ AC_TYPE_SSIZE_T # Checks for library functions. AC_FUNC_MALLOC AC_FUNC_REALLOC -AC_CHECK_FUNCS([gettimeofday memmove memset select strdup png_get_io_ptr]) +AC_CHECK_FUNCS([clock_gettime gettimeofday memmove memset select strdup png_get_io_ptr]) AC_CONFIG_FILES([Makefile]) AC_OUTPUT diff --git a/libguac/include/guacio.h b/libguac/include/guacio.h index 0e70c0ea..86dcd22a 100644 --- a/libguac/include/guacio.h +++ b/libguac/include/guacio.h @@ -118,7 +118,7 @@ GUACIO* guac_open(int fd); * @param i The unsigned int to write. * @return Zero on success, or non-zero if an error occurs while writing. */ -ssize_t guac_write_int(GUACIO* io, unsigned int i); +ssize_t guac_write_int(GUACIO* io, unsigned long i); /** * Writes the given string to the given GUACIO object. The data diff --git a/libguac/include/protocol.h b/libguac/include/protocol.h index 6b631ca3..9a00cb99 100644 --- a/libguac/include/protocol.h +++ b/libguac/include/protocol.h @@ -131,6 +131,15 @@ void guac_send_args(GUACIO* io, const char** name); */ void guac_send_name(GUACIO* io, const char* name); +/** + * Sends a sync instruction over the given GUACIO connection. The + * current time in milliseconds should be passed in as the timestamp. + * + * @param io The GUACIO connection to use. + * @param timestamp The current timestamp (in milliseconds). + */ +void guac_send_sync(GUACIO* io, long timestamp); + /** * Sends an error instruction over the given GUACIO connection. The * error description given will be automatically escaped for diff --git a/libguac/src/client.c b/libguac/src/client.c index ca32c468..89485565 100644 --- a/libguac/src/client.c +++ b/libguac/src/client.c @@ -37,6 +37,11 @@ #include #include +#ifdef HAVE_CLOCK_GETTIME +#include +#else +#include +#endif #include #include @@ -243,11 +248,42 @@ void guac_free_client(guac_client* client) { } +long __guac_current_timestamp() { + +#ifdef HAVE_CLOCK_GETTIME + + struct timespec current; + + /* Get current time */ + clock_gettime(CLOCK_REALTIME, ¤t); + + /* Calculate milliseconds */ + return current.tv_sec * 1000 + current.tv_nsec / 1000000; + +#else + + struct timeval current; + + /* Get current time */ + gettimeofday(¤t, NULL); + + /* Calculate milliseconds */ + return current.tv_sec * 1000 + current.tv_usec / 1000; + +#endif + +} + void guac_start_client(guac_client* client) { GUACIO* io = client->io; guac_instruction instruction; int wait_result; + long last_received_timestamp; + long last_sent_timestamp; + + /* Init timestamps */ + last_received_timestamp = last_sent_timestamp = __guac_current_timestamp(); /* VNC Client Loop */ for (;;) { @@ -255,13 +291,21 @@ void guac_start_client(guac_client* client) { /* Handle server messages */ if (client->handle_messages) { - int retval = client->handle_messages(client); - if (retval) { - GUAC_LOG_ERROR("Error handling server messages"); - return; - } + /* Only handle messages if synced within threshold */ + if (last_sent_timestamp - last_received_timestamp < 200) { - guac_flush(io); + int retval = client->handle_messages(client); + if (retval) { + GUAC_LOG_ERROR("Error handling server messages"); + return; + } + + /* Send sync after updates */ + last_sent_timestamp = __guac_current_timestamp(); + guac_send_sync(io, last_sent_timestamp); + + guac_flush(io); + } } @@ -275,7 +319,15 @@ void guac_start_client(guac_client* client) { do { - if (strcmp(instruction.opcode, "mouse") == 0) { + if (strcmp(instruction.opcode, "sync") == 0) { + last_received_timestamp = atol(instruction.argv[0]); + if (last_received_timestamp > last_sent_timestamp) { + guac_send_error(io, "Received sync from future."); + guac_free_instruction_data(&instruction); + return; + } + } + else if (strcmp(instruction.opcode, "mouse") == 0) { if (client->mouse_handler) if ( client->mouse_handler( diff --git a/libguac/src/guacio.c b/libguac/src/guacio.c index c27fe5a7..c7135cd3 100644 --- a/libguac/src/guacio.c +++ b/libguac/src/guacio.c @@ -97,7 +97,7 @@ ssize_t __guac_write(GUACIO* io, const char* buf, int count) { return retval; } -ssize_t guac_write_int(GUACIO* io, unsigned int i) { +ssize_t guac_write_int(GUACIO* io, unsigned long i) { char buffer[128]; char* ptr = &(buffer[127]); diff --git a/libguac/src/protocol.c b/libguac/src/protocol.c index e942648b..1192cfc7 100644 --- a/libguac/src/protocol.c +++ b/libguac/src/protocol.c @@ -226,6 +226,14 @@ void guac_send_error(GUACIO* io, const char* error) { } +void guac_send_sync(GUACIO* io, long timestamp) { + + guac_write_string(io, "sync:"); + guac_write_int(io, timestamp); + guac_write_string(io, ";"); + +} + void guac_send_copy(GUACIO* io, int srcl, int srcx, int srcy, int w, int h, int dstl, int dstx, int dsty) { guac_write_string(io, "copy:"); guac_write_int(io, srcl);