/*-
* $Id: rr-connection.c,v 1.57 2002/10/06 18:17:03 jonas Exp $
*
* See the file LICENSE for redistribution information.
* If you have not received a copy of the license, please contact CodeFactory
* by email at info@codefactory.se, or on the web at http://www.codefactory.se/
* You may also write to: CodeFactory AB, SE-903 47, Umeå, Sweden.
*
* Copyright (c) 2002 Jonas Borgström <jonas@codefactory.se>
* Copyright (c) 2002 Daniel Lundin <daniel@codefactory.se>
* Copyright (c) 2002 CodeFactory AB. All rights reserved.
*/
#include <librr/rr.h>
#include <string.h>
static GObjectClass *parent_class = NULL;
static void finalize (GObject *object);
static void remove_out_queue_entry (RRConnection *connection, gint idx);
static void
rr_connection_init (GObject *object)
{
RRConnection *conn = (RRConnection *)object;
g_static_rw_lock_init (&conn->channel_lock);
conn->channel_by_id = g_hash_table_new (NULL, NULL);
conn->out_frames = g_queue_new ();
conn->out_queue_lock = g_mutex_new ();
conn->out_queue_cond = g_cond_new ();
conn->out_queue = g_ptr_array_new ();
conn->active_item = 0;
conn->manager = rr_manager_new (0);
rr_channel_set_connection (RR_CHANNEL (conn->manager), conn);
g_static_rw_lock_init (&conn->languages_lock);
conn->languages = NULL;
conn->filter_stack = rr_filterstack_new ();
}
static void
rr_connection_class_init (GObjectClass *klass)
{
klass->finalize = finalize;
parent_class = g_type_class_peek_parent (klass);
/* Register the "BEEP" frame types */
rr_framefactory_register_type ("MSG", RR_TYPE_FRAME);
rr_framefactory_register_type ("RPY", RR_TYPE_FRAME);
rr_framefactory_register_type ("ERR", RR_TYPE_FRAME);
rr_framefactory_register_type ("ANS", RR_TYPE_FRAME);
rr_framefactory_register_type ("NUL", RR_TYPE_FRAME);
}
GType
rr_connection_get_type (void)
{
static GType rr_type = 0;
if (!rr_type) {
static GTypeInfo type_info = {
sizeof (RRConnectionClass),
NULL,
NULL,
(GClassInitFunc) rr_connection_class_init,
NULL,
NULL,
sizeof (RRConnection),
16,
(GInstanceInitFunc) rr_connection_init
};
rr_type = g_type_register_static (G_TYPE_OBJECT, "RRConnection",
&type_info, G_TYPE_FLAG_ABSTRACT);
}
return rr_type;
}
static void
unref_channel (gpointer key, gpointer data, gpointer user_data)
{
g_object_unref (G_OBJECT (data));
}
static void
finalize (GObject *object)
{
RRConnection *conn = (RRConnection *)object;
if (conn->manager)
g_object_unref (G_OBJECT (conn->manager));
g_static_rw_lock_writer_lock (&conn->channel_lock);
g_hash_table_foreach (conn->channel_by_id,
unref_channel, NULL);
g_hash_table_destroy (conn->channel_by_id);
g_static_rw_lock_writer_unlock (&conn->channel_lock);
g_static_rw_lock_free (&conn->channel_lock);
g_mutex_lock (conn->out_queue_lock);
g_list_foreach (conn->out_frames->head, (GFunc)g_object_unref, NULL);
g_queue_free (conn->out_frames);
g_ptr_array_free (conn->out_queue, TRUE);
g_mutex_unlock (conn->out_queue_lock);
g_mutex_free (conn->out_queue_lock);
g_cond_free (conn->out_queue_cond);
g_static_rw_lock_writer_lock (&conn->languages_lock);
g_slist_foreach (conn->languages, (GFunc)g_free, NULL);
g_slist_free (conn->languages);
g_static_rw_lock_writer_unlock (&conn->languages_lock);
g_static_rw_lock_free (&conn->languages_lock);
rr_filterstack_free (conn->filter_stack);
g_slist_foreach (conn->peer_profiles, (GFunc)g_free, NULL);
g_slist_free (conn->peer_profiles);
g_free (conn->server_name);
if (conn->profreg)
g_object_unref (G_OBJECT (conn->profreg));
rr_callback_list_free (conn->quiescence_cb);
parent_class->finalize (object);
}
/**
* rr_connection_register_sender:
* @connection: the #RRConnection object
* @channel: the #RRChannel object
*
* Tells the @connection that @channel has some things to send.
*
**/
void
rr_connection_register_sender (RRConnection *connection, RRChannel *channel)
{
gint i;
g_assert (RR_IS_CHANNEL (channel));
g_assert (RR_IS_CONNECTION (connection));
/* FIXME: return error if the connection isn't established */
g_mutex_lock (connection->out_queue_lock);
/* No point in adding a channel that hasn't anything to send */
if (rr_channel_out_queue_empty (channel)) {
g_mutex_unlock (connection->out_queue_lock);
return;
}
/* Just return if the channel is already registered */
for (i = 0; i < connection->out_queue->len; i++) {
if (channel == g_ptr_array_index (connection->out_queue, i)) {
g_mutex_unlock (connection->out_queue_lock);
return;
}
}
g_ptr_array_add (connection->out_queue, channel);
g_mutex_unlock (connection->out_queue_lock);
if (!connection->output_disabled)
rr_connection_enable_output (connection);
}
/**
* rr_connection_get_channel:
* @connection: a #RRConnection.
* @id: channel id 0..2147483647
*
* Finds and returns the RRChannel instance that has channel @id on @connection.
*
* Return value: a #RRChannel or %NULL.
**/
RRChannel *
rr_connection_get_channel (RRConnection *connection, gint id)
{
RRChannel *channel;
g_static_rw_lock_reader_lock (&connection->channel_lock);
channel = g_hash_table_lookup (connection->channel_by_id,
GINT_TO_POINTER (id));
g_static_rw_lock_reader_unlock (&connection->channel_lock);
return channel;
}
/**
* rr_connection_get_channel_locked:
* @connection: a #RRConnection.
* @id: channel id 0..2147483647
*
* Finds and returns the RRChannel instance that has channel @id on @connection.
* The channel mutex lock is also locked for the returned channel.
*
* Return value: a #RRChannel or %NULL.
**/
RRChannel *
rr_connection_get_channel_locked (RRConnection *connection, gint id)
{
RRChannel *channel;
g_static_rw_lock_reader_lock (&connection->channel_lock);
channel = g_hash_table_lookup (connection->channel_by_id,
GINT_TO_POINTER (id));
if (channel)
g_mutex_lock (channel->mutex);
g_static_rw_lock_reader_unlock (&connection->channel_lock);
return channel;
}
/**
* rr_connection_add_channel:
* @connection: a #RRConnection.
* @channel: a #RRChannel.
*
* Adds @channel to the list of channels started on the @connection.
**/
void
rr_connection_add_channel (RRConnection *conn, RRChannel *channel)
{
g_return_if_fail (RR_IS_CONNECTION (conn));
g_return_if_fail (RR_IS_CHANNEL (channel));
channel->connection = conn;
g_static_rw_lock_writer_lock (&conn->channel_lock);
g_hash_table_insert (conn->channel_by_id, GINT_TO_POINTER(channel->id),
g_object_ref (G_OBJECT (channel)));
g_static_rw_lock_writer_unlock (&conn->channel_lock);
}
static gboolean
remove_helper (gpointer key, gpointer data, gpointer user_data)
{
RRChannel *channel = data;
RRConnection *conn = user_data;
gint i;
g_assert (RR_IS_CHANNEL (channel));
/* A special case for the manager channel */
if (channel->id == 0) {
g_object_unref (G_OBJECT (channel));
return TRUE;
}
rr_channel_lock (channel);
rr_main_work_pool_join (RRWPGROUP (channel));
/* Remove the channel from the "active" list */
g_mutex_lock (conn->out_queue_lock);
for (i = 0; i < conn->out_queue->len; i++) {
if (channel == g_ptr_array_index (conn->out_queue, i)) {
remove_out_queue_entry (conn, i);
break;
}
}
g_mutex_unlock (conn->out_queue_lock);
channel->connection = NULL;
rr_channel_unlock (channel);
g_object_unref (G_OBJECT (channel));
return TRUE;
}
/**
* rr_connection_remove_channel:
* @connection: a #RRConnection.
* @channel: a #RRChannel.
*
* Removes @channel from the list of channels started on the @connection.
**/
void
rr_connection_remove_channel (RRConnection *conn, RRChannel *channel)
{
gint32 id;
g_return_if_fail (RR_IS_CONNECTION (conn));
g_return_if_fail (RR_IS_CHANNEL (channel));
g_static_rw_lock_writer_lock (&conn->channel_lock);
id = channel->id;
remove_helper (NULL, channel, conn);
g_hash_table_remove (conn->channel_by_id, GINT_TO_POINTER (id));
g_static_rw_lock_writer_unlock (&conn->channel_lock);
}
static void
close_all_helper (gpointer key, gpointer data, gpointer user_data)
{
RRChannel *channel = data;
rr_channel_close_confirmation (channel, RR_BEEP_CODE_ABORTED,
NULL, "disconnect()");
}
void
rr_connection_close_all (RRConnection *conn)
{
g_return_if_fail (RR_IS_CONNECTION (conn));
g_static_rw_lock_writer_lock (&conn->channel_lock);
g_hash_table_foreach (conn->channel_by_id, close_all_helper, conn);
g_hash_table_foreach_remove (conn->channel_by_id, remove_helper, conn);
g_static_rw_lock_writer_unlock (&conn->channel_lock);
}
/**
* rr_connection_enable_input:
* @connection: A #RRConnection
*
* Enable processing of incoming BEEP frames.
**/
gboolean
rr_connection_enable_input (RRConnection *connection)
{
if (RR_CONNECTION_GET_CLASS (connection)->enable_input)
return RR_CONNECTION_GET_CLASS (connection)->enable_input (connection);
else
return FALSE;
}
/**
* rr_connection_disable_input:
* @connection: A #RRConnection.
*
* Disable processing of incoming BEEP frames.
**/
gboolean
rr_connection_disable_input (RRConnection *connection)
{
if (RR_CONNECTION_GET_CLASS (connection)->disable_input)
return RR_CONNECTION_GET_CLASS (connection)->disable_input (connection);
else
return FALSE;
}
/**
* rr_connection_enable_output:
* @connection: A #RRConnection.
*
* Enable transmission of enqueued frames/messages.
**/
gboolean
rr_connection_enable_output (RRConnection *connection)
{
connection->output_disabled = FALSE;
if (RR_CONNECTION_GET_CLASS (connection)->enable_output)
return RR_CONNECTION_GET_CLASS (connection)->enable_output (connection);
else
return FALSE;
}
/**
* rr_connection_disable_output:
* @connection: A #RRConnection
*
* Disable transmission of enqueued frames/messages.
**/
gboolean
rr_connection_disable_output (RRConnection *connection)
{
connection->output_disabled = TRUE;
if (RR_CONNECTION_GET_CLASS (connection)->disable_output)
return RR_CONNECTION_GET_CLASS (connection)->disable_output (connection);
else
return FALSE;
}
/**
* rr_connection_set_profile_registry:
* @connection: A #RRConnection.
* @profreg: A #RRProfileRegistry.
*
* Give the @connection a list of profiles to support.
**/
void
rr_connection_set_profile_registry (RRConnection *connection,
RRProfileRegistry *profreg)
{
g_return_if_fail (RR_IS_CONNECTION (connection));
g_return_if_fail (RR_IS_PROFILE_REGISTRY (profreg));
connection->profreg = g_object_ref (G_OBJECT (profreg));
}
static RRFrame *
get_next_frame_from_out_frames (RRConnection *conn)
{
RRFrame *frame;
RRChannel *channel = NULL;
frame = RR_FRAME (g_queue_pop_tail (conn->out_frames));
channel = rr_connection_get_channel (conn, frame->channel_id);
rr_channel_register_frame (channel, frame);
return frame;
}
static RRChannel *
get_active_channel (RRConnection *connection, gint *idx)
{
RRChannel *channel;
*idx = connection->active_item;
channel = g_ptr_array_index (connection->out_queue, *idx);
g_assert (RR_IS_CHANNEL (channel));
connection->active_item++;
connection->active_item %= connection->out_queue->len;
return channel;
}
static void
remove_out_queue_entry (RRConnection *connection, gint idx)
{
g_ptr_array_remove_index (connection->out_queue, idx);
if (connection->active_item > idx)
connection->active_item--;
}
RRFrame *
rr_connection_get_next_frame (RRConnection *conn, gsize buffer_size)
{
GObject *item;
RRChannel *channel;
RRFrame *frame;
gint idx, i;
g_assert (RR_IS_CONNECTION (conn));
g_mutex_lock (conn->out_queue_lock);
/* First look in the out_frames queue, it has higher priority */
if (g_queue_is_empty (conn->out_frames) == FALSE) {
frame = get_next_frame_from_out_frames (conn);
g_mutex_unlock (conn->out_queue_lock);
return frame;
}
/* The out_queue shouldn't be empty */
if (conn->out_queue->len == 0) {
g_mutex_unlock (conn->out_queue_lock);
return NULL;
}
/* Search for the next "active" channel in line for transmission,
skip channels with no transmit window bytes left */
for (i = 0; i < conn->out_queue->len; i++) {
channel = get_active_channel (conn, &idx);
if (channel->window_out == 0 ||
channel->starved == TRUE ||
channel->disabled == TRUE)
continue;
item = rr_channel_get_active_item (channel);
if (RR_IS_FRAME (item)) {
/* Remove the channel entry if it's queue is empty */
if (rr_channel_remove_active_item (channel))
remove_out_queue_entry (conn, idx);
rr_channel_register_frame (channel, RR_FRAME (item));
g_mutex_unlock (conn->out_queue_lock);
return RR_FRAME (item);
}
if (RR_IS_MESSAGE (item)) {
RRMessage *msg = RR_MESSAGE (item);
gsize max_size;
/* The window size might be larger then the output
* buffer size */
max_size = MIN (msg->channel->window_out, buffer_size);
frame = rr_message_get_frame (msg, max_size);
if (frame == NULL) {
/* This indicates that rr_message_get_frame
* thinks that window_out is to small to send
* anything, so we suspend this channel
* until the channel gets a lager window_out */
channel->starved = TRUE;
continue;
}
if (frame->more == FALSE) {
/* Remove the channel entry if it's queue is
* empty */
g_object_unref (G_OBJECT (msg));
if (rr_channel_remove_active_item (channel))
remove_out_queue_entry (conn, idx);
}
rr_channel_register_frame (channel, frame);
g_mutex_unlock (conn->out_queue_lock);
return frame;
}
}
g_mutex_unlock (conn->out_queue_lock);
return NULL;
}
/**
* rr_connection_send_frame:
* @connection: a #RRConnection
* @frame: a #RRFrame
* @error: location to return an error of type RR_ERROR or RR_BEEP_ERROR.
*
* Enqueue a frame to be sent on @connection, this function has higher priority
* then #rr_channel_send_frame and #rr_channel_send_message. So @frame will
* be sent before frames and messages enqueued by those functions.
* Note: The frame will be unref:ed after the transmission.
*
* Return value:
**/
gboolean
rr_connection_send_frame (RRConnection *connection, RRFrame *frame,
GError **error)
{
g_assert (RR_IS_CONNECTION (connection));
g_assert (RR_IS_FRAME (frame));
g_mutex_lock (connection->out_queue_lock);
g_queue_push_head (connection->out_frames, RR_FRAME (frame));
g_mutex_unlock (connection->out_queue_lock);
if (!connection->output_disabled)
rr_connection_enable_output (connection);
return TRUE;
}
/**
* rr_connection_pending_transmissions_p:
* @connection: a #RRConnection
*
* Return value: %TRUE if the out queue is not empty.
**/
gboolean
rr_connection_pending_transmissions_p (RRConnection *connection)
{
gboolean empty = FALSE;
g_mutex_lock (connection->out_queue_lock);
if (connection->out_frames->length == 0 &&
connection->out_queue->len == 0)
empty = TRUE;
g_mutex_unlock (connection->out_queue_lock);
return !empty;
}
/* Note: Returns a copy of the list */
GSList *
rr_connection_get_languages (RRConnection *connection)
{
GSList *langs_copy = NULL;
GSList *lang;
g_static_rw_lock_reader_lock (&connection->languages_lock);
lang = connection->languages;
while (lang) {
langs_copy = g_slist_append (langs_copy, g_strdup (lang->data));
lang = lang->next;
}
g_static_rw_lock_reader_unlock (&connection->languages_lock);
return langs_copy;
}
gchar *
rr_connection_get_languages_str (RRConnection *connection)
{
GSList *lang;
GString *langstr;
gchar *ptr;
g_static_rw_lock_reader_lock (&connection->languages_lock);
lang = connection->languages;
if (lang == NULL) {
g_static_rw_lock_reader_unlock (&connection->languages_lock);
return NULL;
}
langstr = g_string_new ("");
while (lang) {
g_string_append (langstr, (const gchar *)lang->data);
lang = lang->next;
if (lang)
g_string_append (langstr, " ");
}
g_static_rw_lock_reader_unlock (&connection->languages_lock);
ptr = langstr->str;
g_string_free (langstr, FALSE);
return ptr;
}
gboolean
rr_connection_language_supported (RRConnection *connection,
const gchar *lang)
{
gboolean found = FALSE;
g_return_val_if_fail (RR_IS_CONNECTION (connection), FALSE);
g_static_rw_lock_reader_lock (&connection->languages_lock);
if (g_slist_find_custom (connection->languages, lang,
(GCompareFunc)strcmp)) {
found = TRUE;
g_print ("connection::language_supported: "
"Yes, we do indeed speak '%s'.\n", lang);
}
g_static_rw_lock_reader_unlock (&connection->languages_lock);
return found;
}
void
rr_connection_add_language (RRConnection *connection,
const gchar *lang)
{
g_return_if_fail (RR_IS_CONNECTION (connection));
if (!rr_connection_language_supported (connection, lang)) {
g_static_rw_lock_writer_lock (&connection->languages_lock);
connection->languages = g_slist_prepend (connection->languages,
g_strdup (lang));
g_static_rw_lock_writer_unlock (&connection->languages_lock);
}
}
gboolean
rr_connection_remove_language (RRConnection *connection,
const gchar *lang)
{
GSList *item;
gchar *data;
gboolean result = FALSE;
g_return_val_if_fail (RR_IS_CONNECTION (connection), FALSE);
g_static_rw_lock_writer_lock (&connection->languages_lock);
item = g_slist_find_custom (connection->languages, lang,
(GCompareFunc)strcmp);
data = item->data;
if (item) {
connection->languages = g_slist_remove (connection->languages,
data);
g_free (data);
result = TRUE;
}
g_static_rw_lock_writer_unlock (&connection->languages_lock);
return result;
}
/**
* rr_connection_wait_quiescence:
* @connection: A #RRConnection
* @error: location to return an error or %NULL
*
* Blocks until all frames and messages in the out queue are sent.
*
* Return value: %TRUE on success, %FALSE on failure.
**/
gboolean
rr_connection_wait_quiescence (RRConnection *connection, GError **error)
{
g_mutex_lock (connection->out_queue_lock);
while (connection->out_frames->length != 0 ||
connection->out_queue->len != 0) {
if (connection->connected == FALSE) {
g_set_error (error, RR_ERROR, RR_ERROR_OTHER,
"disconnect ()");
g_mutex_unlock (connection->out_queue_lock);
return FALSE;
}
g_cond_wait (connection->out_queue_cond,
connection->out_queue_lock);
}
g_mutex_unlock (connection->out_queue_lock);
return TRUE;
}
/**
* rr_connection_do_quiescence:
* @connection: A #RRConnection
* @callback: a callback function
* @data: data to use as the first argument to the callback function.
* @user_data: data to use as the second argument to the callback function.
*
* The callback function is called called when the outbound queues are empty.
**/
void
rr_connection_do_quiescence (RRConnection *connection, GFunc callback,
gpointer data, gpointer user_data)
{
gboolean do_call = FALSE;
if (connection->connected == FALSE)
return;
g_mutex_lock (connection->out_queue_lock);
if (connection->out_frames->length != 0 ||
connection->out_queue->len != 0)
rr_callback_list_push (&connection->quiescence_cb,
callback, data, user_data);
else if (callback)
do_call = TRUE;
g_mutex_unlock (connection->out_queue_lock);
if (do_call)
callback (data, user_data);
}
static void
warn_channel (gpointer key, gpointer data, gpointer user_data)
{
RRChannel *channel = RR_CHANNEL (data);
GError **error = (GError **)user_data;
if (error && *error)
return;
if (channel->id != 0) {
rr_channel_close_indication (RR_CHANNEL (data), 200, NULL,
"Tuning reset", error);
}
}
/**
* rr_connection_begin_tuning_reset:
* @connection: a #RRConnection
* @error: location to return an error of type RR_ERROR or RR_BEEP_ERROR.
*
* Warns the active channels that a tuning reset is pending by invoking
* rr_channel_close_indication. If no channel objects then the @connection
* gets ready to receive a new greeting message.
*
* Return value: %TRUE on success, %FALSE on failure.
**/
gboolean
rr_connection_begin_tuning_reset (RRConnection *connection, GError **error)
{
RRManager *manager = RR_MANAGER (connection->manager);
/* Call close_indication for all open channels */
g_static_rw_lock_reader_lock (&connection->channel_lock);
g_hash_table_foreach (connection->channel_by_id, warn_channel,
error);
g_static_rw_lock_reader_unlock (&connection->channel_lock);
if (error && *error)
return FALSE;
/* FIXME: should we send a SEQ frame here */
rr_manager_set_expects_greeting (manager, TRUE);
rr_manager_set_greeting_sent (manager, FALSE);
return TRUE;
}
static gboolean
reset_channel (gpointer key, gpointer data, gpointer user_data)
{
RRChannel *channel = RR_CHANNEL (data);
/* Don't close the manager channel */
if (channel->id != 0) {
rr_channel_lock (channel);
rr_channel_close_confirmation (channel, 200, NULL,
"Tuning reset");
rr_channel_unlock (channel);
g_object_unref (G_OBJECT (channel));
return TRUE;
}
else
return FALSE;
}
static void
do_complete_tuning_reset (gpointer data, gpointer user_data)
{
RRConnection *connection = RR_CONNECTION (data);
RRManager *manager;
manager = RR_MANAGER (connection->manager);
/* Call close_confirmation and unref all channels */
g_static_rw_lock_writer_lock (&connection->channel_lock);
g_hash_table_foreach_remove (connection->channel_by_id, reset_channel,
NULL);
g_static_rw_lock_writer_unlock (&connection->channel_lock);
rr_manager_send_greeting (manager, NULL);
}
/**
* rr_connection_complete_tuning_reset:
* @connection: the #RRConnection.
* @channel: the channel that is tuning.
*
* Closes all open channels on @connection. Sends a new greeting and waits
* until a greeting from the other peer is received.
*
**/
void
rr_connection_complete_tuning_reset (RRConnection *connection,
RRChannel *channel)
{
g_object_ref (G_OBJECT (channel));
rr_connection_do_quiescence (connection, do_complete_tuning_reset,
connection, NULL);
rr_main_work_pool_push (0, (GFunc)g_object_unref, channel, NULL);
}
/**
* rr_connection_set_peer_profiles:
* @connection: The #RRConnection.
* @list: a list of supported profiles.
*
* Store a list of peer supported profiles in the @connection object.
**/
void
rr_connection_set_peer_profiles (RRConnection *connection, GSList *list)
{
g_slist_foreach (connection->peer_profiles, (GFunc)g_free, NULL);
g_slist_free (connection->peer_profiles);
connection->peer_profiles = list;
}
/**
* rr_connection_get_peer_profiles:
* @connection: The #RRConnection
*
* Returns a list of profile uri's that the remote peer supports.
*
* Return value: A const pointer to the profile list.
**/
const GSList *
rr_connection_get_peer_profiles (RRConnection *connection)
{
return connection->peer_profiles;
}
/**
* rr_connection_peer_supports_profile:
* @connection: The #RRConnection.
* @profile: A profile type.
*
* Determines if the remote peer supports the @profile.
*
* Return value: TRUE if the @profile is supported else FALSE.
**/
gboolean
rr_connection_peer_supports_profile (RRConnection *connection,
GType profile)
{
const gchar *uri;
g_return_val_if_fail (g_type_is_a (profile, RR_TYPE_CHANNEL), FALSE);
uri = rr_channel_get_uri (profile);
g_return_val_if_fail (uri != NULL, FALSE);
return g_slist_find_custom (connection->peer_profiles, uri,
(GCompareFunc)strcmp) != NULL;
}
/**
* rr_connection_get_server_name:
* @connection: The #RRConnection.
*
* Returns the "serverName" attribute for the first successful "start" element
* received by a BEEP peer is meaningful for the duration of the BEEP
* session.
*
* Return value: the %serverName.
**/
const gchar *
rr_connection_get_server_name (RRConnection *connection)
{
g_return_val_if_fail (RR_IS_CONNECTION (connection), NULL);
return connection->server_name;
}
/**
* rr_connection_set_server_name:
* @connection: The #RRConnection.
* @server_name: a %serverName.
*
* Sets the serverName that is received from the BEEP peer.
**/
void
rr_connection_set_server_name (RRConnection *connection, const gchar *server_name)
{
g_return_if_fail (RR_IS_CONNECTION (connection));
g_free (connection->server_name);
if (server_name)
connection->server_name = g_strdup (server_name);
}
/**
* rr_connection_disconnect:
* @connection: A #RRConnection
* @error: @error: location to return an error of type G_IO_ERROR, RR_ERROR or
* RR_BEEP_ERROR.
*
* Attempts to close the connection.
* NOTE: connection will be unref:ed.
*
* Return value: %TRUE on success, %FALSE on failure.
**/
gboolean
rr_connection_disconnect (RRConnection *connection, GError **error)
{
return RR_CONNECTION_GET_CLASS (connection)->disconnect (connection,
error);
}
/**
* rr_connection_get_manager:
* @connection: A #RRConnection.
*
* Returns the manager channel (channel 0) for the given @connection.
*
* Return value: the #RRManager channel associated with this connection.
**/
RRManager *
rr_connection_get_manager (RRConnection *connection)
{
g_return_val_if_fail (RR_IS_CONNECTION (connection), NULL);
return RR_MANAGER (connection->manager);
}
/**
* rr_connection_start:
* @connection: The #RRConnection.
* @server_name: # The server_name parameter or NULL.
* @profile_type: The profile type to start.
* @config_data: Profile specific config data or NULL.
* @error: location to return an error of type RR_ERROR or RR_BEEP_ERROR
*
* Tries to create a new channel of the provided profile type.
*
* Return value: A #RRProfile on success, %NULL on failure.
**/
RRChannel *
rr_connection_start (RRConnection *connection, const gchar *server_name,
GType profile_type, gpointer config_data, GError **error)
{
g_return_val_if_fail (RR_IS_CONNECTION (connection), NULL);
g_return_val_if_fail (RR_IS_MANAGER (connection->manager), NULL);
return rr_manager_start_multi (connection->manager, server_name, error,
profile_type, config_data,
G_TYPE_INVALID);
}
/**
* rr_connection_start_multi:
* @connection: The #RRConnection.
* @server_name: The server_name parameter or NULL.
* @error: location to return an error of type RR_ERROR or RR_BEEP_ERROR
* @...: A list of Profile type + config_data pairs and a G_TYPE_INVALID at the
* end.
*
* Tries to create a new channel with one of the provided profiles.
*
* Return value: A #RRProfile on success, %NULL on failure.
**/
RRChannel *
rr_connection_start_multi (RRConnection *connection, const gchar *server_name,
GError **error, ...)
{
RRChannel *ret;
va_list args;
g_return_val_if_fail (RR_IS_CONNECTION (connection), NULL);
g_return_val_if_fail (RR_IS_MANAGER (connection->manager), NULL);
va_start (args, error);
ret = rr_manager_start_multiv (connection->manager, server_name, error, args);
va_end (args);
return ret;
}
syntax highlighted by Code2HTML, v. 0.9.1