/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef _GUAC_CLIENT_H #define _GUAC_CLIENT_H /** * Functions and structure contents for the Guacamole proxy client. * * @file client.h */ #include "client-fntypes.h" #include "client-types.h" #include "client-constants.h" #include "layer-types.h" #include "object-types.h" #include "pool-types.h" #include "socket-types.h" #include "stream-types.h" #include "timestamp-types.h" #include "user-fntypes.h" #include "user-types.h" #include #include #include struct guac_client { /** * The guac_socket structure to be used to communicate with all connected * web-clients (users). Unlike the user-level guac_socket, this guac_socket * will broadcast instructions to all connected users simultaneously. It * is expected that the implementor of any Guacamole proxy client will * provide their own mechanism of I/O for their protocol. The guac_socket * structure is used only to communicate conveniently with the Guacamole * web-client. */ guac_socket* socket; /** * The current state of the client. When the client is first allocated, * this will be initialized to GUAC_CLIENT_RUNNING. It will remain at * GUAC_CLIENT_RUNNING until an event occurs which requires the client to * shutdown, at which point the state becomes GUAC_CLIENT_STOPPING. */ guac_client_state state; /** * Arbitrary reference to proxy client-specific data. Implementors of a * Guacamole proxy client can store any data they want here, which can then * be retrieved as necessary in the message handlers. */ void* data; /** * The time (in milliseconds) that the last sync message was sent to the * client. */ guac_timestamp last_sent_timestamp; /** * Handler for freeing data when the client is being unloaded. * * This handler will be called when the client needs to be unloaded * by the proxy, and any data allocated by the proxy client should be * freed. * * Note that this handler will NOT be called if the client's * guac_client_init() function fails. * * Implement this handler if you store data inside the client. * * Example: * @code * int free_handler(guac_client* client); * * int guac_client_init(guac_client* client) { * client->free_handler = free_handler; * } * @endcode */ guac_client_free_handler* free_handler; /** * Logging handler. This handler will be called via guac_client_log() when * the client needs to log messages of any type. * * 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, guac_client_log_level level, const char* format, va_list args); * * void function_of_daemon() { * * guac_client* client = [pass log_handler to guac_client_plugin_get_client()]; * * } * @endcode */ guac_client_log_handler* log_handler; /** * Pool of buffer indices. Buffers are simply layers with negative indices. * Note that because guac_pool always gives non-negative indices starting * at 0, the output of this guac_pool will be adjusted. */ guac_pool* __buffer_pool; /** * Pool of layer indices. Note that because guac_pool always gives * non-negative indices starting at 0, the output of this guac_pool will * be adjusted. */ guac_pool* __layer_pool; /** * Pool of stream indices. */ guac_pool* __stream_pool; /** * All available client-level output streams (data going to all connected * users). */ guac_stream* __output_streams; /** * The unique identifier allocated for the connection, which may * be used within the Guacamole protocol to refer to this connection. * This identifier is guaranteed to be unique from all existing * connections and will not collide with any available protocol * names. */ char* connection_id; /** * Lock which is acquired when the users list is being manipulated, or when * the users list is being iterated. */ pthread_rwlock_t __users_lock; /** * The first user within the list of all connected users, or NULL if no * users are currently connected. */ guac_user* __users; /** * The user that first created this connection. This user will also have * their "owner" flag set to a non-zero value. If the owner has left the * connection, this will be NULL. */ guac_user* __owner; /** * The number of currently-connected users. This value may include inactive * users if cleanup of those users has not yet finished. */ int connected_users; /** * Handler for join events, called whenever a new user is joining an active * connection. Note that because users may leave the connection at any * time, a reference to a guac_user can become invalid at any time and * should never be maintained outside the scope of a function invoked by * libguac to which that guac_user was passed (the scope in which the * guac_user reference is guaranteed to be valid) UNLESS that reference is * properly invalidated within the leave_handler. * * The handler is given a pointer to a newly-allocated guac_user which * must then be initialized, if needed. * * Example: * @code * int join_handler(guac_user* user, int argc, char** argv); * * int guac_client_init(guac_client* client) { * client->join_handler = join_handler; * } * @endcode */ guac_user_join_handler* join_handler; /** * Handler for leave events, called whenever a new user is leaving an * active connection. * * The handler is given a pointer to the leaving guac_user whose custom * data and associated resources must now be freed, if any. * * Example: * @code * int leave_handler(guac_user* user); * * int guac_client_init(guac_client* client) { * client->leave_handler = leave_handler; * } * @endcode */ guac_user_leave_handler* leave_handler; /** * NULL-terminated array of all arguments accepted by this client , in * order. New users will specify these arguments when they join the * connection, and the values of those arguments will be made available to * the function initializing newly-joined users. * * The guac_client_init entry point is expected to initialize this, if * arguments are expected. * * Example: * @code * const char* __my_args[] = { * "hostname", * "port", * "username", * "password", * NULL * }; * * int guac_client_init(guac_client* client) { * client->args = __my_args; * } * @endcode */ const char** args; /** * Handle to the dlopen()'d plugin, which should be given to dlclose() when * this client is freed. This is only assigned if guac_client_load_plugin() * is used. */ void* __plugin_handle; }; /** * Returns a new, barebones guac_client. This new guac_client has no handlers * set, but is otherwise usable. * * @return A pointer to the new client. */ guac_client* guac_client_alloc(); /** * Free all resources associated with the given client. * * @param client The proxy client to free all reasources of. */ void guac_client_free(guac_client* client); /** * Writes a 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 logging this message. * @param level The level at which to log this message. * @param format A printf-style format string to log. * @param ... Arguments to use when filling the format string for printing. */ void guac_client_log(guac_client* client, guac_client_log_level level, const char* format, ...); /** * Writes a 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 logging this message. * @param level The level at which to log this message. * @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(guac_client* client, guac_client_log_level level, const char* format, va_list ap); /** * Signals the given client to stop gracefully. This is a completely * cooperative signal, and can be ignored by the client or the hosting * daemon. * * @param client The proxy client to signal to stop. */ void guac_client_stop(guac_client* client); /** * Signals the given client to stop gracefully, while also signalling via the * Guacamole protocol that an error has occurred. Note that this is a completely * cooperative signal, and can be ignored by the client or the hosting * daemon. The message given will be logged to the system logs. * * @param client The proxy client to signal to stop. * @param status The status to send over the Guacamole protocol. * @param format A printf-style format string to log. * @param ... Arguments to use when filling the format string for printing. */ void guac_client_abort(guac_client* client, guac_protocol_status status, const char* format, ...); /** * Signals the given client to stop gracefully, while also signalling via the * Guacamole protocol that an error has occurred. Note that this is a completely * cooperative signal, and can be ignored by the client or the hosting * daemon. The message given will be logged to the system logs. * * @param client The proxy client to signal to stop. * @param status The status to send over the Guacamole protocol. * @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_abort(guac_client* client, guac_protocol_status status, const char* format, va_list ap); /** * Allocates a new buffer (invisible layer). An arbitrary index is * automatically assigned if no existing buffer is available for use. * * @param client The proxy client to allocate the buffer for. * @return The next available buffer, or a newly allocated buffer. */ guac_layer* guac_client_alloc_buffer(guac_client* client); /** * Allocates a new layer. An arbitrary index is automatically assigned * if no existing layer is available for use. * * @param client The proxy client to allocate the layer buffer for. * @return The next available layer, or a newly allocated layer. */ guac_layer* guac_client_alloc_layer(guac_client* client); /** * Returns the given buffer to the pool of available buffers, such that it * can be reused by any subsequent call to guac_client_allow_buffer(). * * @param client The proxy client to return the buffer to. * @param layer The buffer to return to the pool of available buffers. */ void guac_client_free_buffer(guac_client* client, guac_layer* layer); /** * Returns the given layer to the pool of available layers, such that it * can be reused by any subsequent call to guac_client_allow_layer(). * * @param client The proxy client to return the layer to. * @param layer The buffer to return to the pool of available layer. */ void guac_client_free_layer(guac_client* client, guac_layer* layer); /** * Allocates a new stream. An arbitrary index is automatically assigned * if no previously-allocated stream is available for use. * * @param client * The client to allocate the stream for. * * @return * The next available stream, or a newly allocated stream. */ guac_stream* guac_client_alloc_stream(guac_client* client); /** * Returns the given stream to the pool of available streams, such that it * can be reused by any subsequent call to guac_client_alloc_stream(). * * @param client * The client to return the stream to. * * @param stream * The stream to return to the pool of available stream. */ void guac_client_free_stream(guac_client* client, guac_stream* stream); /** * Adds the given user to the internal list of connected users. Future writes * to the broadcast socket stored within guac_client will also write to this * user. The join handler of this guac_client will be called. * * @param client The proxy client to add the user to. * @param user The user to add. * @param argc The number of arguments to pass to the new user. * @param argv An array of strings containing the argument values being passed. * @return Zero if the user was added successfully, non-zero if the user could * not join the connection. */ int guac_client_add_user(guac_client* client, guac_user* user, int argc, char** argv); /** * Removes the given user, removing the user from the internally-tracked list * of connected users, and calling any appropriate leave handler. * * @param client The proxy client to return the buffer to. * @param user The user to remove. */ void guac_client_remove_user(guac_client* client, guac_user* user); /** * Calls the given function on all currently-connected users of the given * client. The function will be given a reference to a guac_user and the * specified arbitrary data. The value returned by the callback will be * ignored. * * This function is reentrant, but the user list MUST NOT be manipulated * within the same thread as a callback to this function. Though the callback * MAY invoke guac_client_foreach_user(), doing so should not be necessary, and * may indicate poor design choices. * * @param client * The client whose users should be iterated. * * @param callback * The function to call for each user. * * @param data * Arbitrary data to pass to the callback each time it is invoked. */ void guac_client_foreach_user(guac_client* client, guac_user_callback* callback, void* data); /** * Calls the given function with the currently-connected user that is marked as * the owner. The owner of a connection is the user that established the * initial connection that created the connection (the first user to connect * and join). The function will be given a reference to the guac_user and the * specified arbitrary data. If the owner has since left the connection, the * function will instead be invoked with NULL as the guac_user. The value * returned by the callback will be returned by this function. * * This function is reentrant, but the user list MUST NOT be manipulated * within the same thread as a callback to this function. * * @param client * The client to retrieve the owner from. * * @param callback * The callback to invoke on the user marked as the owner of the * connection. NULL will be passed to this callback instead if there is no * owner. * * @param data * Arbitrary data to pass to the given callback. * * @return * The value returned by the callback. */ void* guac_client_for_owner(guac_client* client, guac_user_callback* callback, void* data); /** * Calls the given function with the given user ONLY if they are currently * connected. The function will be given a reference to the guac_user and the * specified arbitrary data. If the provided user doesn't exist or has since * left the connection, the function will instead be invoked with NULL as the * guac_user. The value returned by the callback will be returned by this * function. * * This function is reentrant, but the user list MUST NOT be manipulated * within the same thread as a callback to this function. * * @param client * The client that the given user is expected to be associated with. * * @param user * The user to provide to the given callback if valid. The pointer need not * even point to properly allocated memory; the user will only be passed to * the callback function if they are valid, and the provided user pointer * will not be dereferenced during this process. * * @param callback * The callback to invoke on the given user if they are valid. NULL will be * passed to this callback instead if the user is not valid. * * @param data * Arbitrary data to pass to the given callback. * * @return * The value returned by the callback. */ void* guac_client_for_user(guac_client* client, guac_user* user, guac_user_callback* callback, void* data); /** * Marks the end of the current frame by sending a "sync" instruction to * all connected users. This instruction will contain the current timestamp. * The last_sent_timestamp member of guac_client will be updated accordingly. * * If an error occurs sending the instruction, a non-zero value is * returned, and guac_error is set appropriately. * * @param client The guac_client which has finished a frame. * @return Zero on success, non-zero on error. */ int guac_client_end_frame(guac_client* client); /** * Initializes the given guac_client using the initialization routine provided * by the plugin corresponding to the named protocol. This will automatically * invoke guac_client_init within the plugin for the given protocol. * * Note that the connection will likely not be established until the first * user (the "owner") is added to the client. * * @param client The guac_client to initialize. * @param protocol The name of the protocol to use. * @return Zero if initialization was successful, non-zero otherwise. */ int guac_client_load_plugin(guac_client* client, const char* protocol); /** * Calculates and returns the approximate processing lag experienced by the * pool of users. The processing lag is the difference in time between server * and client due purely to data processing and excluding network delays. * * @param client * The guac_client to calculate the processing lag of. * * @return * The approximate processing lag of the pool of users associated with the * given guac_client, in milliseconds. */ int guac_client_get_processing_lag(guac_client* client); /** * Streams the given connection parameter value over an argument value stream * ("argv" instruction), exposing the current value of the named connection * parameter to all users of the given client. The argument value stream will * be automatically allocated and freed. * * @param client * The Guacamole client for which the argument value stream should be * allocated. * * @param socket * The socket over which instructions associated with the argument value * stream should be sent. * * @param mimetype * The mimetype of the data within the connection parameter value being * sent. * * @param name * The name of the connection parameter being sent. * * @param value * The current value of the connection parameter being sent. */ void guac_client_stream_argv(guac_client* client, guac_socket* socket, const char* mimetype, const char* name, const char* value); /** * Streams the image data of the given surface over an image stream ("img" * instruction) as PNG-encoded data. The image stream will be automatically * allocated and freed. * * @param client * The Guacamole client for which the image stream should be allocated. * * @param socket * The socket over which instructions associated with the image stream * should be sent. * * @param mode * The composite mode to use when rendering the image over the given layer. * * @param layer * The destination layer. * * @param x * The X coordinate of the upper-left corner of the destination rectangle * within the given layer. * * @param y * The Y coordinate of the upper-left corner of the destination rectangle * within the given layer. * * @param surface * A Cairo surface containing the image data to be streamed. */ void guac_client_stream_png(guac_client* client, guac_socket* socket, guac_composite_mode mode, const guac_layer* layer, int x, int y, cairo_surface_t* surface); /** * Streams the image data of the given surface over an image stream ("img" * instruction) as JPEG-encoded data at the given quality. The image stream * will be automatically allocated and freed. * * @param client * The Guacamole client for which the image stream should be allocated. * * @param socket * The socket over which instructions associated with the image stream * should be sent. * * @param mode * The composite mode to use when rendering the image over the given layer. * * @param layer * The destination layer. * * @param x * The X coordinate of the upper-left corner of the destination rectangle * within the given layer. * * @param y * The Y coordinate of the upper-left corner of the destination rectangle * within the given layer. * * @param surface * A Cairo surface containing the image data to be streamed. * * @param quality * The JPEG image quality, which must be an integer value between 0 and 100 * inclusive. Larger values indicate improving quality at the expense of * larger file size. */ void guac_client_stream_jpeg(guac_client* client, guac_socket* socket, guac_composite_mode mode, const guac_layer* layer, int x, int y, cairo_surface_t* surface, int quality); /** * Streams the image data of the given surface over an image stream ("img" * instruction) as WebP-encoded data at the given quality. The image stream * will be automatically allocated and freed. If the server does not support * WebP, this function has no effect, so be sure to check the result of * guac_client_supports_webp() prior to calling this function. * * @param client * The Guacamole client for whom the image stream should be allocated. * * @param socket * The socket over which instructions associated with the image stream * should be sent. * * @param mode * The composite mode to use when rendering the image over the given layer. * * @param layer * The destination layer. * * @param x * The X coordinate of the upper-left corner of the destination rectangle * within the given layer. * * @param y * The Y coordinate of the upper-left corner of the destination rectangle * within the given layer. * * @param surface * A Cairo surface containing the image data to be streamed. * * @param quality * The WebP image quality, which must be an integer value between 0 and 100 * inclusive. For lossy images, larger values indicate improving quality at * the expense of larger file size. For lossless images, this dictates the * quality of compression, with larger values producing smaller files at * the expense of speed. * * @param lossless * Zero to encode a lossy image, non-zero to encode losslessly. */ void guac_client_stream_webp(guac_client* client, guac_socket* socket, guac_composite_mode mode, const guac_layer* layer, int x, int y, cairo_surface_t* surface, int quality, int lossless); /** * Returns whether all users of the given client support WebP. If any user does * not support WebP, or the server cannot encode WebP images, zero is returned. * * @param client * The Guacamole client whose users should be checked for WebP support. * * @return * Non-zero if the all users of the given client claim to support WebP and * the server has been built with WebP support, zero otherwise. */ int guac_client_supports_webp(guac_client* client); /** * The default Guacamole client layer, layer 0. */ extern const guac_layer* GUAC_DEFAULT_LAYER; #endif