| <?xml version="1.0" encoding="UTF-8"?> |
| <chapter xml:id="libguac" xmlns="http://docbook.org/ns/docbook" version="5.0" |
| xml:lang="en" xmlns:xl="http://www.w3.org/1999/xlink" |
| xmlns:xi="http://www.w3.org/2001/XInclude"> |
| <title>libguac</title> |
| <indexterm> |
| <primary>API</primary> |
| <secondary>C</secondary> |
| </indexterm> |
| <indexterm> |
| <primary>libguac</primary> |
| </indexterm> |
| <para>The C API for extending and developing with Guacamole is libguac. All |
| native components produced by the Guacamole project link with this |
| library, and this library provides the common basis for extending the |
| native functionality of those native components (by implementing client |
| plugins).</para> |
| <para>libguac is used mainly for developing client plugins like |
| libguac-client-vnc or libguac-client-rdp, or for developing a proxy |
| supporting the Guacamole protocol like guacd. This chapter is intended |
| to give an overview of how libguac is used, and how to use it for |
| general communication with the Guacamole protocol.</para> |
| <section xml:id="libguac-error-handling"> |
| <title>Error handling</title> |
| <para>Most functions within libguac handle errors by returning a zero or |
| non-zero value, whichever is appropriate for the function at hand. |
| If an error is encountered, the <varname>guac_error</varname> |
| variable is set appropriately, and |
| <varname>guac_error_message</varname> contains a |
| statically-allocated human-readable string describing the context of |
| the error. These variables intentionally mimic the functionality |
| provided by <varname>errno</varname> and |
| <filename>errno.h</filename>.</para> |
| <para>Both <varname>guac_error</varname> and |
| <varname>guac_error_message</varname> are defined within |
| <filename>error.h</filename>. A human-readable string describing |
| the error indicated by <varname>guac_error</varname> can be |
| retrieved using <methodname>guac_status_string()</methodname>, which |
| is also statically allocated.</para> |
| <para>If functions defined within client plugins set |
| <varname>guac_error</varname> and |
| <varname>guac_error_message</varname> appropriately when errors |
| are encountered, the messages logged to syslog by guacd will be more |
| meaningful for both users and developers.</para> |
| </section> |
| <section xml:id="libguac-client-plugins"> |
| <title>Client plugins</title> |
| <para>Client plugins are libraries loaded dynamically using the |
| functions of libdl. Each client plugin is required to follow a |
| naming convention, where the name of the library is |
| <package>libguac-client-<replaceable>PROTOCOL</replaceable></package>. |
| Failing to do this means that guacd will be unable to find the |
| library when the client plugin needs to be loaded.</para> |
| <para>To load a client plugin, guacd calls the guac_client_plugin_open() |
| function with the name of the protocol corresponding to the plugin |
| to be loaded. Upon success, |
| <methodname>guac_client_plugin_open()</methodname> returns a |
| handle to the library containing the client plugin within an |
| instance of <classname>guac_client_plugin</classname>. This instance |
| will eventually be cleaned up by |
| <methodname>guac_client_plugin_close()</methodname> when guacd |
| is finished using it. While these functions are intended to be used |
| by guacd, there is no reason they cannot be used in another proxy |
| implementation, even if that proxy implementation resides within |
| another client plugin.</para> |
| <para>Once the client plugin is successfully loaded, guacd makes a call |
| to <methodname>guac_client_plugin_init_client()</methodname> to |
| initialize the client. This function calls the |
| <methodname>guac_client_init()</methodname> function within the |
| client plugin which absolutely all client plugins must define. This |
| function is the entry point of all client plugins, similar to the |
| <methodname>main()</methodname> function of a C program.</para> |
| <para>As guacd handles the handshake procedure required by the Guacamole |
| protocol, it reads a statically-allocated, |
| <constant>NULL</constant>-terminated set of argument names declared |
| within the client plugin: <varname>GUAC_CLIENT_ARGS</varname>. As |
| with <methodname>guac_client_init()</methodname>, all client plugins |
| must define this variable if they are to work. As the handshake |
| procedure is completed, guacd will initialize and populate a |
| <classname>guac_client</classname> structure, including the |
| <classname>guac_client_info</classname> structure contained |
| within it, and pass it to |
| <methodname>guac_client_init()</methodname> along with the |
| argument count and argument values received by the connecting |
| client.</para> |
| <para>It is the duty of the client plugin implementation to populate the |
| event handlers of the <classname>guac_client</classname> it receives |
| as applicable. Once this is done, and the |
| <methodname>guac_client_init()</methodname> function returns |
| successfully, communication with the connected client begins, and |
| guacd will invoke the event handlers of the |
| <classname>guac_client</classname> as necessary for any |
| instruction received.</para> |
| </section> |
| <section xml:id="libguac-layers"> |
| <title>Layers and buffers</title> |
| <para>The main operand of all drawing instructions is the layer, |
| represented within libguac by the <classname>guac_layer</classname> |
| structure. Each <classname>guac_layer</classname> is normally |
| allocated using <methodname>guac_client_alloc_layer()</methodname> |
| or <methodname>guac_client_alloc_buffer()</methodname>, depending on |
| whether a layer or buffer is desired, and freed with |
| <methodname>guac_client_free_layer()</methodname> or |
| <methodname>guac_client_free_buffer()</methodname>.</para> |
| <important> |
| <para>Care must be taken to invoke the allocate and free pairs of |
| each type of layer correctly. |
| <methodname>guac_client_free_layer()</methodname> should |
| only be used to free layers allocated with |
| <methodname>guac_client_alloc_layer()</methodname>, and |
| <methodname>guac_client_free_buffer()</methodname> should |
| only be used to free layers allocated with |
| <methodname>guac_client_alloc_buffer()</methodname>, all |
| called using the same instance of |
| <classname>guac_client</classname>.</para> |
| <para>If these restrictions are not observed, the effect of invoking |
| these functions is undefined.</para> |
| </important> |
| <para>Using these layer management functions allows you to reuse |
| existing layers or buffers after their original purpose has expired, |
| thus conserving resources on the client side, as allocation of new |
| layers within the remote client is a relatively expensive |
| operation.</para> |
| <para>It is through layers and buffers that Guacamole provides support |
| for hardware-accelerated compositing and cached updates. Creative |
| use of layers and buffers leads to efficient updates on the client |
| side, which usually translates into speed and responsiveness.</para> |
| <para>Regardless of whether you allocate new layers or buffers, there is |
| always one layer guaranteed to be present: the default layer, |
| represented by libguac as <varname>GUAC_DEFAULT_LAYER</varname>. If |
| you only wish to affect to the main display of the connected client |
| somehow, this is the layer you want to use as the operand of your |
| drawing instruction.</para> |
| </section> |
| <section xml:id="libguac-sending-instructions"> |
| <title>Sending instructions</title> |
| <para>All drawing in Guacamole is accomplished through the sending of |
| instructions to the connected client using the Guacamole protocol. |
| The same goes for streaming audio, video, or file content. All |
| features and content supported by Guacamole ultimately reduces to |
| one or more instructions which are part of the documented |
| protocol.</para> |
| <para>Most drawing using libguac is done using Cairo functions on a |
| <classname>cairo_surface_t</classname> (see the Cairo API |
| documentation) which is later used in a png instruction, sent via |
| <methodname>guac_protocol_send_png()</methodname>. Cairo was |
| chosen as a dependency of libguac to provide developers an existing |
| and stable means of drawing to image buffers which will ultimately |
| be sent as easy-to-digest PNG images.</para> |
| <para>The Guacamole protocol also supports drawing primitives similar to |
| those present in the Cairo API and HTML5's canvas tag. These |
| instructions are documented individually in the Guacamole Protocol |
| Reference in a section dedicated to drawing instructions, and like |
| all Guacamole protocol instructions, each instruction has a |
| corresponding function in libguac following the naming convention |
| <methodname>guac_protocol_send_<replaceable>OPCODE</replaceable>()</methodname>.</para> |
| <para>Each protocol function takes a <classname>guac_socket</classname> |
| as an argument, which is the buffered I/O object used by libguac. |
| The <classname>guac_socket</classname> corresponding to the |
| connected client is stored within the socket member of the |
| <classname>guac_client</classname> object in use, for |
| example:</para> |
| <informalexample> |
| <programlisting>guac_protocol_send_size(client->socket, GUAC_DEFAULT_LAYER, 1024, 768);</programlisting> |
| </informalexample> |
| </section> |
| <section xml:id="libguac-protocol-nesting"> |
| <title>Protocol nesting</title> |
| <para>When large instructions need to be sent, particularly those |
| associated with audio or video, it is best to send those |
| instructions broken into individual packets using nest instructions, |
| such that the larger instruction can be interleaved with the smaller |
| instructions such that normal responsiveness is not lessened. As |
| future instructions cannot be parsed until the earlier instructions |
| finish parsing, avoiding large instructions is important if the user |
| is expected to interact with their display in real-time.</para> |
| <para>libguac provides rudimentary means of automatically nesting |
| instructions using the <methodname>guac_socket_nest()</methodname> |
| function. This function returns a new |
| <classname>guac_socket</classname> which writes data to nest |
| instructions to its parent <classname>guac_socket</classname>, |
| rather than to the client's stream directly. By using this and the |
| piecemeal versions of the instruction-sending functions required, |
| audio or video data can be stretched over multiple instructions |
| rather than one single instruction:</para> |
| <informalexample> |
| <programlisting>/* Get nested socket */ |
| guac_socket* nested_socket = guac_socket_nest(client->socket, 0); |
| |
| /* Write audio header */ |
| guac_protocol_send_audio_header(nested_socket, |
| 0, "audio/ogg", 250, buffer_size); |
| |
| ... |
| |
| /* Write data packets */ |
| guac_protocol_send_audio_data(nested_socket, data, sizeof(data)); |
| |
| ... |
| |
| /* Finish audio instruction */ |
| guac_protocol_send_audio_end(nested_socket); |
| |
| /* When done, close the socket */ |
| guac_socket_close(nested_socket);</programlisting> |
| </informalexample> |
| <para>Providing that calls to guac_protocol_send_audio_data() (or the |
| similar video functions) are made interleaved with calls to smaller |
| instructions, those smaller instructions will not be blocked by the |
| size of the audio data that must be sent.</para> |
| <important> |
| <para>Because of the nature of the Guacamole protocol, the size and |
| duration of audio or video data must be known beforehand. If |
| audio or video data must be streamed in real-time, it will need |
| to be divided into individual self-contained chunks. Smaller |
| chunks have a greater chance of causing noticeable gaps due to |
| network hiccups, but are more responsive and will seem more |
| in-line with what is happening from the user's perspective, |
| while larger chunks will be less vulnerable to network issues, |
| but obviously will require the client to wait for a longer time |
| before the audio or video actually starts playing.</para> |
| <para>Note that the size of each audio or video packet is not |
| related to the size of each nest instruction. Choosing larger |
| audio or video packets does not mean that the nest instruction |
| cannot be used; in fact, this is the purpose of the nest |
| instruction: to allow larger instructions to be broken up into |
| smaller instructions.</para> |
| </important> |
| </section> |
| <section xml:id="libguac-event-handling"> |
| <title>Event handling</title> |
| <para>Generally, as guacd receives instructions from the connected |
| client, it invokes event handlers if set within the associated |
| <classname>guac_client</classname> instance. These handlers |
| correspond to the instructions received, which in turn correspond to |
| events which occur on the client side. The only exception to this is |
| when guacd wishes to give the client plugin control and allow it to |
| handle any messages that may have arrived from the remote desktop |
| server, in which case it invokes a specific event handler dedicated |
| to this purpose.</para> |
| <section xml:id="libguac-key-events"> |
| <title>Key events</title> |
| <para>When keys are pressed or released on the client side, the |
| client sends key instructions to the server. These instructions |
| are parsed and handled by calling the key event handler |
| installed in the <property>key_handler</property> member of the |
| <classname>guac_client</classname>. This key handler is |
| given the keysym of the key that was changed, and a boolean |
| value indicating whether the key was pressed or released.</para> |
| <informalexample> |
| <programlisting>int key_handler(guac_client* client, int keysym, int pressed) { |
| /* Do something */ |
| } |
| |
| ... |
| |
| /* Within guac_client_init */ |
| client->key_handler = key_handler;</programlisting> |
| </informalexample> |
| </section> |
| <section xml:id="libguac-mouse-events"> |
| <title>Mouse events</title> |
| <para>When the mouse is moved, and buttons are pressed or released, |
| the client sends mouse instructions to the server. These |
| instructions are parsed and handled by calling the mouse event |
| handler installed in the <property>mouse_handler</property> |
| member of the <classname>guac_client</classname>. This mouse |
| handler is given the current X and Y coordinates of the mouse |
| pointer, as well as a mask indicating which buttons are pressed |
| and which are released.</para> |
| <informalexample> |
| <programlisting>int mouse_handler(guac_client* client, int x, int y, int button_mask) { |
| /* Do something */ |
| } |
| |
| ... |
| |
| /* Within guac_client_init */ |
| client->mouse_handler = mouse_handler;</programlisting> |
| </informalexample> |
| <para>The file <filename>client.h</filename> also defines the mask |
| of each button for convenience:</para> |
| <variablelist> |
| <varlistentry> |
| <term><constant>GUAC_CLIENT_MOUSE_LEFT</constant></term> |
| <listitem> |
| <para>The left mouse button, set when pressed.</para> |
| </listitem> |
| </varlistentry> |
| <varlistentry> |
| <term><constant>GUAC_CLIENT_MOUSE_MIDDLE</constant></term> |
| <listitem> |
| <para>The middle mouse button, set when pressed.</para> |
| </listitem> |
| </varlistentry> |
| <varlistentry> |
| <term><constant>GUAC_CLIENT_MOUSE_RIGHT</constant></term> |
| <listitem> |
| <para>The right mouse button, set when pressed.</para> |
| </listitem> |
| </varlistentry> |
| <varlistentry> |
| <term><constant>GUAC_CLIENT_MOUSE_UP</constant></term> |
| <listitem> |
| <para>The button corresponding to one scroll in the |
| upwards direction of the mouse scroll wheel, set |
| when scrolled.</para> |
| </listitem> |
| </varlistentry> |
| <varlistentry> |
| <term><constant>GUAC_CLIENT_MOUSE_DOWN</constant></term> |
| <listitem> |
| <para>The button corresponding to one scroll in the |
| downwards direction of the mouse scroll wheel, set |
| when scrolled.</para> |
| </listitem> |
| </varlistentry> |
| </variablelist> |
| </section> |
| <section xml:id="libguac-clipboard-events"> |
| <title>Clipboard events</title> |
| <para>If the client sends data which should be sent to the clipboard |
| of the remote desktop, guacd will trigger the clipboard handler |
| installed in the <property>clipboard_handler</property> member |
| of the <classname>guac_client</classname>.</para> |
| <informalexample> |
| <programlisting>int clipboard_handler(guac_client* client, char* text) { |
| /* Do something */ |
| } |
| |
| ... |
| |
| /* Within guac_client_init */ |
| client->clipboard_handler = clipboard_handler;</programlisting> |
| </informalexample> |
| <para>The data given will always be a |
| <constant>NULL</constant>-terminated string of UTF8-encoded |
| text. The Guacamole protocol does not yet support clipboard data |
| in other formats.</para> |
| </section> |
| <section xml:id="libguac-message-handling"> |
| <title>Handling server messages</title> |
| <para>A client plugin implementation is expected to only handle |
| server messages when control is given to it via a call to the |
| message handler installed in the |
| <property>handle_messages</property> member of the |
| <classname>guac_client</classname>. While it might seem |
| intuitive to simply create a thread which handles server message |
| in the background, it is important that you do not do this, as |
| guacd pays attention to the exchange of sync instructions back |
| and forth between itself and the client to determine if the |
| client is under load or falling behind due to network problems, |
| and will restrict how frequently the message handler is called |
| accordingly. Ignoring this can lead to the client being |
| overwhelmed with instructions, leading to a bad user |
| experience.</para> |
| <para>The message handler is simpler than all the other handlers, |
| receiving only a pointer to the current |
| <classname>guac_client</classname>:</para> |
| <informalexample> |
| <programlisting>int message_handler(guac_client* client) { |
| /* Handle server messages */ |
| } |
| |
| ... |
| |
| /* Within guac_client_init */ |
| client->handle_messages = message_handler;</programlisting> |
| </informalexample> |
| </section> |
| </section> |
| </chapter> |