blob: 2da697fed1104c2dcf654a775d74b00d0594c27d [file] [log] [blame]
/*
* 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_SOCKET_H
#define _GUAC_SOCKET_H
/**
* Defines the guac_socket object and functionss for using and manipulating it.
*
* @file socket.h
*/
#include "client-types.h"
#include "socket-constants.h"
#include "socket-fntypes.h"
#include "socket-types.h"
#include "timestamp-types.h"
#include <pthread.h>
#include <stdint.h>
#include <unistd.h>
struct guac_socket {
/**
* Arbitrary socket-specific data.
*/
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.
*/
guac_socket_write_handler* write_handler;
/**
* Handler which will be called whenever this socket needs to be flushed.
*/
guac_socket_flush_handler* flush_handler;
/**
* Handler which will be called whenever a socket needs to be acquired for
* exclusive access, such as when an instruction is about to be written.
*/
guac_socket_lock_handler* lock_handler;
/**
* Handler which will be called whenever exclusive access to a socket is
* being released, such as when an instruction has finished being written.
*/
guac_socket_unlock_handler* unlock_handler;
/**
* Handler which will be called whenever guac_socket_select() is invoked
* on this socket.
*/
guac_socket_select_handler* select_handler;
/**
* Handler which will be called when the socket is free'd (closed).
*/
guac_socket_free_handler* free_handler;
/**
* The current state of this guac_socket.
*/
guac_socket_state state;
/**
* The timestamp associated with the time the last block of data was
* written to this guac_socket.
*/
guac_timestamp last_write_timestamp;
/**
* The number of bytes present in the base64 "ready" buffer.
*/
int __ready;
/**
* The base64 "ready" buffer. Once this buffer is filled, base64 data is
* flushed to the main write buffer.
*/
int __ready_buf[3];
/**
* Whether automatic keep-alive is enabled.
*/
int __keep_alive_enabled;
/**
* The keep-alive thread.
*/
pthread_t __keep_alive_thread;
};
/**
* 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);
/**
* Declares that the given socket must automatically send a keep-alive ping
* to ensure neither side of the socket times out while the socket is open.
* This ping will take the form of a "nop" instruction.
*
* @param socket
* The guac_socket to declare as requiring an automatic keep-alive ping.
*/
void guac_socket_require_keep_alive(guac_socket* socket);
/**
* Marks the beginning of a Guacamole protocol instruction.
*
* @param socket
* The guac_socket beginning an instruction.
*/
void guac_socket_instruction_begin(guac_socket* socket);
/**
* Marks the end of a Guacamole protocol instruction.
*
* @param socket
* The guac_socket ending an instruction.
*/
void guac_socket_instruction_end(guac_socket* socket);
/**
* Allocates and initializes a new guac_socket object with the given open
* file descriptor. The file descriptor will be automatically closed when
* the allocated guac_socket is freed.
*
* If an error occurs while allocating the guac_socket object, NULL is returned,
* and guac_error is set appropriately.
*
* @param fd An open file descriptor that this guac_socket object should manage.
* @return A newly allocated guac_socket object associated with the given
* file descriptor, or NULL if an error occurs while allocating
* the guac_socket object.
*/
guac_socket* guac_socket_open(int fd);
/**
* Allocates and initializes a new guac_socket which writes all data via
* nest instructions to the given existing, open guac_socket. Freeing the
* returned guac_socket has no effect on the underlying, nested guac_socket.
*
* If an error occurs while allocating the guac_socket object, NULL is returned,
* and guac_error is set appropriately.
*
* @deprecated
* The "nest" instruction and the corresponding guac_socket
* implementation are no longer necessary, having been replaced by
* the streaming instructions ("blob", "ack", "end"). Code using nested
* sockets or the "nest" instruction should instead write to a normal
* socket directly.
*
* @param parent The guac_socket this new guac_socket should write nest
* instructions to.
* @param index The stream index to use for the written nest instructions.
* @return A newly allocated guac_socket object associated with the given
* guac_socket and stream index, or NULL if an error occurs while
* allocating the guac_socket object.
*/
guac_socket* guac_socket_nest(guac_socket* parent, int index);
/**
* Allocates and initializes a new guac_socket which delegates all socket
* operations to the given primary socket, while simultaneously duplicating all
* written data to the secondary socket. Freeing the returned guac_socket will
* free both primary and secondary sockets.
*
* Return values (error codes) will come only from the primary socket. Locks
* (like those used by guac_socket_instruction_begin() and
* guac_socket_instruction_end()) will affect only the primary socket.
*
* If an error occurs while allocating the guac_socket object, NULL is returned,
* and guac_error is set appropriately.
*
* @param primary
* The primary guac_socket to which all socket operations should be
* delegated. The error codes returned by socket operations, if any, will
* always come from this socket. This socket will also be the only socket
* locked when instructions begin (or unlocked when instructions end).
*
* @param secondary
* The secondary guac_socket to which all data written to the primary
* guac_socket should be copied. If an error prevents the write from
* succeeding, that error will be ignored. Only errors from the primary
* guac_socket will be acknowledged.
*
* @return
* A newly allocated guac_socket object associated with the given primary
* and secondary sockets, or NULL if an error occurs while allocating the
* guac_socket object.
*/
guac_socket* guac_socket_tee(guac_socket* primary, guac_socket* secondary);
/**
* Allocates and initializes a new guac_socket which duplicates all
* instructions written across the sockets of each connected user of the given
* guac_client. The returned socket is a write-only socket. Attempts to read
* from the socket will fail. If a write occurs while no users are connected,
* that write will simply be dropped.
*
* Return values (error codes) from each user's socket will not affect the
* in-progress write, but each failing user will be forcibly stopped with
* guac_user_stop().
*
* If an error occurs while allocating the guac_socket object, NULL is returned,
* and guac_error is set appropriately.
*
* @param client
* The client associated with the group of connected users across which
* duplicates of all instructions should be written.
*
* @return
* A write-only guac_socket object which broadcasts copies of all
* instructions written across all connected users of the given
* guac_client, or NULL if an error occurs while allocating the guac_socket
* object.
*/
guac_socket* guac_socket_broadcast(guac_client* client);
/**
* Writes the given unsigned int to the given guac_socket object. 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 i The unsigned int to write.
* @return Zero on success, or non-zero if an error occurs while writing.
*/
ssize_t guac_socket_write_int(guac_socket* socket, int64_t i);
/**
* Writes the given string to the given guac_socket object. 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 str The string to write.
* @return Zero on success, or non-zero if an error occurs while writing.
*/
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
* 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
* base64 data) can be made.
*
* 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_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, void* buf, size_t count);
/**
* Flushes the base64 buffer, writing padding characters as necessary.
*
* 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 flush
* @return Zero on success, or non-zero if an error occurs during flush.
*/
ssize_t guac_socket_flush_base64(guac_socket* socket);
/**
* Flushes the write buffer.
*
* 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 flush
* @return Zero on success, or non-zero if an error occurs during flush.
*/
ssize_t guac_socket_flush(guac_socket* socket);
/**
* Waits for input to be available on the given guac_socket object until the
* specified timeout elapses.
*
* If an error occurs while waiting, a negative value is returned, and
* guac_error is set appropriately.
*
* If a timeout occurs while waiting, zero value is returned, and
* guac_error is set to GUAC_STATUS_INPUT_TIMEOUT.
*
* @param socket The guac_socket object to wait for.
* @param usec_timeout The maximum number of microseconds to wait for data, or
* -1 to potentially wait forever.
* @return Positive on success, zero if the timeout elapsed and no data is
* available, negative on error.
*/
int guac_socket_select(guac_socket* socket, int usec_timeout);
#endif