xeme/xeme

Implement XemeConnection

6 months ago, Gary Kramlich
19f8cef54b13
Parents 62de723fb97c
Children 0d07defce79b
Implement XemeConnection
--- a/xeme/meson.build Thu Dec 07 21:44:47 2023 -0600
+++ b/xeme/meson.build Fri Dec 08 00:05:46 2023 -0600
@@ -1,5 +1,6 @@
XEME_SOURCES = [
'xemeaddress.c',
+ 'xemeconnection.c',
'xemeinputstream.c',
'xememessage.c',
'xemeoutputstream.c',
@@ -10,6 +11,8 @@
XEME_HEADERS = [
'xemeaddress.h',
+ 'xemeconnection.h',
+ 'xemeconstants.h',
'xemecore.h',
'xemeinputstream.h',
'xememessage.h',
@@ -54,12 +57,28 @@
XEME_BUILT_HEADERS += xeme_h
###############################################################################
+# Enums
+###############################################################################
+XEME_ENUM_HEADERS = [
+ 'xemeconnection.h',
+]
+
+xeme_enums = gnome.mkenums_simple(
+ 'xemeenums',
+ sources : XEME_ENUM_HEADERS,
+ install_header : true,
+ install_dir : get_option('includedir') / 'xeme-1.0' / 'xeme')
+
+XEME_GENERATED_SOURCES += xeme_enums[0]
+XEME_BUILT_HEADERS += xeme_enums[1]
+
+###############################################################################
# Library Target
###############################################################################
xeme_inc = include_directories('.')
xeme_lib = library('xeme',
- XEME_SOURCES + XEME_HEADERS,
+ XEME_SOURCES + XEME_HEADERS + XEME_GENERATED_SOURCES + XEME_BUILT_HEADERS,
c_args : ['-DXEME_COMPILATION', '-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="Xeme"'],
gnu_symbol_visibility : 'hidden',
dependencies : [gio_dep, glib_dep, gobject_dep],
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xeme/xemeconnection.c Fri Dec 08 00:05:46 2023 -0600
@@ -0,0 +1,558 @@
+/*
+ * Copyright (C) 2023 Xeme Developers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "xemeconnection.h"
+
+#include "xemeaddress.h"
+#include "xemeconstants.h"
+#include "xemeenums.h"
+#include "xemestring.h"
+
+enum {
+ PROP_0,
+ PROP_JID,
+ PROP_RESOURCE,
+ PROP_SERVER,
+ PROP_PORT,
+ PROP_TLS_MODE,
+ N_PROPERTIES,
+};
+static GParamSpec *properties[N_PROPERTIES] = {NULL, 0};
+
+struct _XemeConnection {
+ GObject parent;
+
+ char *jid;
+ char *domain; /* This is parsed out of the jid when it is set. */
+ char *resource;
+
+ char *server;
+ guint16 port;
+
+ XemeTlsMode tls_mode;
+
+ GSocketClient *client;
+ GSocketConnection *socket_connection;
+
+ XemeInputStream *input;
+
+ GCancellable *cancellable;
+};
+
+G_DEFINE_TYPE(XemeConnection, xeme_connection, G_TYPE_OBJECT)
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static void
+xeme_connection_set_jid(XemeConnection *connection, const char *jid) {
+ char *bare_jid = NULL;
+ char *domain = NULL;
+ char *resource = NULL;
+
+ if(!xeme_address_parse(jid, &bare_jid, NULL, &domain, &resource)) {
+ g_critical("invalid jid '%s'", jid);
+
+ return;
+ }
+
+ g_free(connection->jid);
+ connection->jid = bare_jid;
+ connection->domain = domain;
+
+ if(resource != NULL) {
+ xeme_connection_set_resource(connection, resource);
+ g_free(resource);
+ }
+}
+
+static void
+xeme_connection_connect_success(XemeConnection *connection, GTask *task) {
+ XemeOutputStream *output = NULL;
+ GError *error = NULL;
+ GIOStream *iostream = NULL;
+ GInputStream *istream = NULL;
+ GOutputStream *ostream = NULL;
+
+ iostream = G_IO_STREAM(connection->socket_connection);
+
+ istream = g_io_stream_get_input_stream(iostream);
+ if(!xeme_input_stream_start(connection->input, istream, &error)) {
+ g_task_return_error(task, error);
+ g_clear_object(&task);
+
+ xeme_connection_close(connection, NULL);
+
+ return;
+ }
+
+ ostream = g_io_stream_get_output_stream(iostream);
+ output = xeme_output_stream_new(connection->domain, connection->jid,
+ connection->cancellable);
+ if(!xeme_output_stream_start(output, ostream, &error)) {
+ g_task_return_error(task, error);
+
+ xeme_connection_close(connection, NULL);
+ } else {
+ g_task_return_pointer(task, output, g_object_unref);
+ }
+
+ g_clear_object(&task);
+}
+
+/******************************************************************************
+ * connect_to_host functions
+ *****************************************************************************/
+static void
+xeme_connection_connect_to_host_cb(GObject *source, GAsyncResult *result,
+ gpointer data)
+{
+ XemeConnection *connection = NULL;
+ GError *error = NULL;
+ GSocketClient *client = G_SOCKET_CLIENT(source);
+ GSocketConnection *socket_connection = NULL;
+ GTask *task = data;
+
+ connection = g_task_get_source_object(task);
+ socket_connection = g_socket_client_connect_to_host_finish(client, result,
+ &error);
+ if(error != NULL) {
+ g_task_return_error(task, error);
+ g_clear_object(&task);
+
+ return;
+ }
+
+ connection->socket_connection = socket_connection;
+
+ xeme_connection_connect_success(connection, task);
+}
+
+static void
+xeme_connection_connect_to_host(XemeConnection *connection, GTask *task) {
+ gboolean use_tls = FALSE;
+ const char *server = NULL;
+
+ g_return_if_fail(XEME_IS_CONNECTION(connection));
+ g_return_if_fail(G_IS_TASK(task));
+
+ use_tls = (connection->tls_mode == XEME_TLS_MODE_DIRECT_TLS);
+ g_socket_client_set_tls(connection->client, use_tls);
+
+ server = connection->server;
+ if(xeme_str_is_empty(server)) {
+ server = connection->domain;
+ }
+
+ g_socket_client_connect_to_host_async(connection->client,
+ server,
+ connection->port,
+ connection->cancellable,
+ xeme_connection_connect_to_host_cb,
+ task);
+}
+
+/******************************************************************************
+ * connect_to_service functions
+ *****************************************************************************/
+static void
+xeme_connection_connect_to_service_cb(GObject *source, GAsyncResult *result,
+ gpointer data)
+{
+ XemeConnection *connection = NULL;
+ GError *error = NULL;
+ GSocketClient *client = G_SOCKET_CLIENT(source);
+ GSocketConnection *socket_connection = NULL;
+ GTask *task = data;
+
+ connection = g_task_get_source_object(task);
+ socket_connection = g_socket_client_connect_to_service_finish(client,
+ result,
+ &error);
+ if(error != NULL) {
+ g_warning("failed to connect via srv record, attempting direct "
+ "connect.");
+
+ xeme_connection_connect_to_host(connection, task);
+
+ return;
+ }
+
+ connection->socket_connection = socket_connection;
+
+ xeme_connection_connect_success(connection, task);
+}
+
+static void
+xeme_connection_connect_to_service(XemeConnection *connection, GTask *task) {
+ gboolean use_tls = TRUE;
+ const char *service = XEME_SERVICE_XMPPS_CLIENT;
+
+ g_return_if_fail(XEME_IS_CONNECTION(connection));
+ g_return_if_fail(G_IS_TASK(task));
+
+ if(connection->tls_mode != XEME_TLS_MODE_DIRECT_TLS) {
+ service = XEME_SERVICE_XMPP_CLIENT;
+ use_tls = FALSE;
+ }
+
+ g_socket_client_set_tls(connection->client, use_tls);
+
+ g_socket_client_connect_to_service_async(connection->client,
+ connection->domain,
+ service,
+ connection->cancellable,
+ xeme_connection_connect_to_service_cb,
+ task);
+}
+
+/******************************************************************************
+ * GObject Implementation
+ *****************************************************************************/
+static void
+xeme_connection_finalize(GObject *obj) {
+ XemeConnection *connection = XEME_CONNECTION(obj);
+
+ xeme_connection_close(connection, NULL);
+
+ g_clear_pointer(&connection->jid, g_free);
+ g_clear_pointer(&connection->domain, g_free);
+ g_clear_pointer(&connection->resource, g_free);
+ g_clear_pointer(&connection->server, g_free);
+
+ g_clear_object(&connection->client);
+ g_clear_object(&connection->socket_connection);
+
+ g_clear_object(&connection->cancellable);
+
+ G_OBJECT_CLASS(xeme_connection_parent_class)->finalize(obj);
+}
+
+static void
+xeme_connection_get_property(GObject *obj, guint param_id, GValue *value,
+ GParamSpec *pspec)
+{
+ XemeConnection *connection = XEME_CONNECTION(obj);
+
+ switch(param_id) {
+ case PROP_JID:
+ g_value_set_string(value, xeme_connection_get_jid(connection));
+ break;
+ case PROP_RESOURCE:
+ g_value_set_string(value, xeme_connection_get_resource(connection));
+ break;
+ case PROP_SERVER:
+ g_value_set_string(value, xeme_connection_get_server(connection));
+ break;
+ case PROP_PORT:
+ g_value_set_uint(value, xeme_connection_get_port(connection));
+ break;
+ case PROP_TLS_MODE:
+ g_value_set_enum(value, xeme_connection_get_tls_mode(connection));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+ break;
+ }
+}
+
+static void
+xeme_connection_set_property(GObject *obj, guint param_id, const GValue *value,
+ GParamSpec *pspec)
+{
+ XemeConnection *connection = XEME_CONNECTION(obj);
+
+ switch(param_id) {
+ case PROP_JID:
+ xeme_connection_set_jid(connection, g_value_get_string(value));
+ break;
+ case PROP_RESOURCE:
+ xeme_connection_set_resource(connection, g_value_get_string(value));
+ break;
+ case PROP_SERVER:
+ xeme_connection_set_server(connection, g_value_get_string(value));
+ break;
+ case PROP_PORT:
+ xeme_connection_set_port(connection, g_value_get_uint(value));
+ break;
+ case PROP_TLS_MODE:
+ xeme_connection_set_tls_mode(connection, g_value_get_enum(value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+ break;
+ }
+}
+
+static void
+xeme_connection_init(G_GNUC_UNUSED XemeConnection *connection) {
+}
+
+static void
+xeme_connection_class_init(XemeConnectionClass *klass) {
+ GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+
+ obj_class->finalize = xeme_connection_finalize;
+ obj_class->get_property = xeme_connection_get_property;
+ obj_class->set_property = xeme_connection_set_property;
+
+ /**
+ * XemeConnection:jid:
+ *
+ * The "Jabber ID" which this connection originates from.
+ *
+ * Since: 0.1.0
+ */
+ properties[PROP_JID] = g_param_spec_string(
+ "jid", "jid",
+ "The jabber id of the originator of this connection.",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * XemeConnection:resource:
+ *
+ * The "resource" for the originator of this connection.
+ *
+ * If the `jid` passed to [ctor@Connection.new] includes a resource, it will be
+ * parsed out and saved here.
+ *
+ * If this %NULL during connection, @connection will request one from the
+ * server and store it here which should be saved by the application.
+ *
+ * Resources are mostly deprecated, but this property can be modify to set
+ * it to whatever you like.
+ *
+ * Since: 0.1.0
+ */
+ properties[PROP_RESOURCE] = g_param_spec_string(
+ "resource", "resource",
+ "The resource for the originator of this connection.",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * XemeConnection:server:
+ *
+ * An explicit server to connect to.
+ *
+ * If this is set, it will be the only connection attempt made. See
+ * [method@Connection.connect_async] for more information.
+ *
+ * Since: 0.1.0
+ */
+ properties[PROP_SERVER] = g_param_spec_string(
+ "server", "server",
+ "An explicit server to connect to.",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * XemeConnection:port:
+ *
+ * The explicit port to use.
+ *
+ * This will only be used if [property@Connection:server] is not %NULL.
+ *
+ * Since: 0.1.0
+ */
+ properties[PROP_PORT] = g_param_spec_uint(
+ "port", "port",
+ "An explicit port to use.",
+ 0, G_MAXUINT16, XEME_PORT_TLS,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ /**
+ * XemeConnection:tls-mode:
+ *
+ * The TLS mode to use for this connection.
+ *
+ * This determines whether or not a TLS connection is attempted at all or
+ * if STARTTLS is used to upgrade a clear connection.
+ *
+ * Since: 0.1.0
+ */
+ properties[PROP_TLS_MODE] = g_param_spec_enum(
+ "tls-mode", "tls-mode",
+ "The mode of TLS to use for this connection.",
+ XEME_TYPE_TLS_MODE,
+ XEME_TLS_MODE_DIRECT_TLS,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
+}
+
+/******************************************************************************
+ * Public API
+ *****************************************************************************/
+XemeConnection *
+xeme_connection_new(const char *jid) {
+ g_return_val_if_fail(!xeme_str_is_empty(jid), NULL);
+
+ return g_object_new(
+ XEME_TYPE_CONNECTION,
+ "jid", jid,
+ NULL);
+}
+
+const char *
+xeme_connection_get_jid(XemeConnection *connection) {
+ g_return_val_if_fail(XEME_IS_CONNECTION(connection), NULL);
+
+ return connection->jid;
+}
+
+const char *
+xeme_connection_get_resource(XemeConnection *connection) {
+ g_return_val_if_fail(XEME_IS_CONNECTION(connection), NULL);
+
+ return connection->resource;
+}
+
+void
+xeme_connection_set_resource(XemeConnection *connection, const char *resource)
+{
+ g_return_if_fail(XEME_IS_CONNECTION(connection));
+
+ if(!xeme_str_equal(connection->resource, resource)) {
+ g_free(connection->resource);
+ connection->resource = g_strdup(resource);
+
+ g_object_notify_by_pspec(G_OBJECT(connection),
+ properties[PROP_RESOURCE]);
+ }
+}
+
+const char *
+xeme_connection_get_server(XemeConnection *connection) {
+ g_return_val_if_fail(XEME_IS_CONNECTION(connection), NULL);
+
+ return connection->server;
+}
+
+void
+xeme_connection_set_server(XemeConnection *connection, const char *server) {
+ g_return_if_fail(XEME_IS_CONNECTION(connection));
+
+ if(!xeme_str_equal(connection->server, server)) {
+ g_free(connection->server);
+ connection->server = g_strdup(server);
+
+ g_object_notify_by_pspec(G_OBJECT(connection),
+ properties[PROP_SERVER]);
+ }
+}
+
+guint16
+xeme_connection_get_port(XemeConnection *connection) {
+ g_return_val_if_fail(XEME_IS_CONNECTION(connection), 0);
+
+ return connection->port;
+}
+
+void
+xeme_connection_set_port(XemeConnection *connection, guint16 port) {
+ g_return_if_fail(XEME_IS_CONNECTION(connection));
+
+ if(connection->port != port) {
+ connection->port = port;
+
+ g_object_notify_by_pspec(G_OBJECT(connection), properties[PROP_PORT]);
+ }
+}
+
+XemeTlsMode
+xeme_connection_get_tls_mode(XemeConnection *connection) {
+ g_return_val_if_fail(XEME_IS_CONNECTION(connection), XEME_TLS_MODE_DIRECT_TLS);
+
+ return connection->tls_mode;
+}
+
+void
+xeme_connection_set_tls_mode(XemeConnection *connection, XemeTlsMode tls_mode)
+{
+ g_return_if_fail(XEME_IS_CONNECTION(connection));
+
+ if(connection->tls_mode != tls_mode) {
+ connection->tls_mode = tls_mode;
+
+ g_object_notify_by_pspec(G_OBJECT(connection),
+ properties[PROP_TLS_MODE]);
+ }
+}
+
+void
+xeme_connection_connect_async(XemeConnection *connection,
+ XemeInputStream *input,
+ GProxyResolver *resolver,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer data)
+{
+ GTask *task = NULL;
+
+ g_return_if_fail(XEME_IS_CONNECTION(connection));
+ g_return_if_fail(XEME_IS_INPUT_STREAM(input));
+
+ if(G_IS_CANCELLABLE(cancellable)) {
+ connection->cancellable = g_object_ref(cancellable);
+ }
+
+ connection->input = g_object_ref(input);
+
+ connection->client = g_socket_client_new();
+ if(G_IS_PROXY_RESOLVER(resolver)) {
+ g_socket_client_set_proxy_resolver(connection->client, resolver);
+ g_clear_object(&resolver);
+ }
+
+ task = g_task_new(connection, cancellable, callback, data);
+
+ /* We're doing a direct connect to a server. */
+ if(!xeme_str_is_empty(connection->server)) {
+ xeme_connection_connect_to_host(connection, task);
+ } else {
+ xeme_connection_connect_to_service(connection, task);
+ }
+}
+
+XemeOutputStream *
+xeme_connection_connect_finish(XemeConnection *connection,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail(XEME_IS_CONNECTION(connection), FALSE);
+ g_return_val_if_fail(G_IS_ASYNC_RESULT(result), FALSE);
+
+ return g_task_propagate_pointer(G_TASK(result), error);
+}
+
+gboolean
+xeme_connection_close(XemeConnection *connection, GError **error) {
+ g_return_val_if_fail(XEME_IS_CONNECTION(connection), FALSE);
+
+ if(G_IS_IO_STREAM(connection->socket_connection)) {
+ /* We're shutting down so we ignore errors. */
+ g_io_stream_close(G_IO_STREAM(connection->socket_connection), NULL,
+ error);
+ g_clear_object(&connection->socket_connection);
+ }
+
+ g_clear_object(&connection->input);
+
+ return TRUE;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xeme/xemeconnection.h Fri Dec 08 00:05:46 2023 -0600
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2023 Xeme Developers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef XEME_CONNECTION_H
+#define XEME_CONNECTION_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gio/gio.h>
+
+#include "xemeinputstream.h"
+#include "xemeoutputstream.h"
+#include "xemeversion.h"
+
+G_BEGIN_DECLS
+
+#define XEME_TYPE_CONNECTION (xeme_connection_get_type())
+
+XEME_AVAILABLE_IN_0_1
+G_DECLARE_FINAL_TYPE(XemeConnection, xeme_connection, XEME, CONNECTION,
+ GObject)
+
+/**
+ * XemeTlsMode:
+ * @XEME_TLS_MODE_DIRECT_TLS: Use direct TLS.
+ * @XEME_TLS_MODE_START_TLS: Use start TLS.
+ * @XEME_TLS_MODE_NONE: Don't use TLS. This should really only be used in rare
+ * circumstances like development.
+ *
+ * An enumeration representing which mode of TLS to use.
+ *
+ * Since: 0.1.0
+ */
+typedef enum {
+ XEME_TLS_MODE_DIRECT_TLS,
+ XEME_TLS_MODE_START_TLS,
+ XEME_TLS_MODE_NONE,
+} XemeTlsMode;
+
+/**
+ * xeme_connection_new:
+ * @jid: (not nullable): The JID of the originator of this connection.
+ *
+ * Creates a new input stream.
+ *
+ * If @jid includes a
+ * [resource](https://www.rfc-editor.org/rfc/rfc6122#section-2), it will be
+ * parsed out and stored in [property@Connection:resource].
+ *
+ * Returns: (transfer full): The new instance.
+ *
+ * Since: 0.1.0
+ */
+XEME_AVAILABLE_IN_0_1
+XemeConnection *xeme_connection_new(const char *jid);
+
+/**
+ * xeme_connection_get_jid:
+ * @connection: The instance.
+ *
+ * Gets the bare [JID](https://www.rfc-editor.org/rfc/rfc6122#section-2) from
+ * @connection.
+ *
+ * Returns: The bare jid.
+ *
+ * Since: 0.1.0
+ */
+const char *xeme_connection_get_jid(XemeConnection *connection);
+
+/**
+ * xeme_connection_get_resource:
+ * @connection: The instance.
+ *
+ * Gets the resource from @connection.
+ *
+ * This may be %NULL in rare circumstances. However, @connection will request a
+ * JID from the server during connection if this is %NULL.
+ *
+ * Returns: (transfer none) (nullable): The resource if set otherwise %NULL.
+ *
+ * Since: 0.1.0
+ */
+XEME_AVAILABLE_IN_0_1
+const char *xeme_connection_get_resource(XemeConnection *connection);
+
+/**
+ * xeme_connection_set_resource:
+ * @connection: The instance.
+ * @resource: (not nullable): The new resource.
+ *
+ * Sets the resource of @connection to @resource.
+ *
+ * Since: 0.1.0
+ */
+XEME_AVAILABLE_IN_0_1
+void xeme_connection_set_resource(XemeConnection *connection, const char *resource);
+
+/**
+ * xeme_connection_get_cancellable:
+ * @connection: The instance.
+ *
+ * Gets the [class@Gio.Cancellable] for @connection.
+ *
+ * Returns: (transfer none) (nullable): The canncellable if one is set,
+ * otherwise %NULL.
+ *
+ * Since: 0.1.0
+ */
+XEME_AVAILABLE_IN_0_1
+GCancellable *xeme_connection_get_cancellable(XemeConnection *connection);
+
+/**
+ * xeme_connection_get_server:
+ * @connection: The instance.
+ *
+ * Gets the explicit server that @connection should connect to.
+ *
+ * See [method@Connection.connect_async] for more information.
+ *
+ * Returns: (nullable): The explicit server to connect to or %NULL.
+ *
+ * Since: 0.1.0
+ */
+XEME_AVAILABLE_IN_0_1
+const char *xeme_connection_get_server(XemeConnection *connection);
+
+/**
+ * xeme_connection_set_server:
+ * @connection: The instance.
+ * @server: (nullable): The new explicit server to connect to.
+ *
+ * Sets the explicit server to connect to.
+ *
+ * Passing %NULL for @server will unset any previous value.
+ *
+ * Since: 0.1.0
+ */
+XEME_AVAILABLE_IN_0_1
+void xeme_connection_set_server(XemeConnection *connection, const char *server);
+
+/**
+ * xeme_connection_get_port:
+ * @connection: The instance.
+ *
+ * Gets the port from @connection.
+ *
+ * Returns: The port to use.
+ *
+ * Since: 0.1.0
+ */
+XEME_AVAILABLE_IN_0_1
+guint16 xeme_connection_get_port(XemeConnection *connection);
+
+/**
+ * xeme_connection_set_port:
+ * @connection: The instance.
+ * @port: The new port value.
+ *
+ * Sets the port to use for @connection to @port.
+ *
+ * Since: 0.1.0
+ */
+XEME_AVAILABLE_IN_0_1
+void xeme_connection_set_port(XemeConnection *connection, guint16 port);
+
+/**
+ * xeme_connection_get_tls_mode:
+ * @connection: The instance.
+ *
+ * Gets the [enum@TlsMode] from @connection.
+ *
+ * Returns: The TLS mode to use.
+ *
+ * Since: 0.1.0
+ */
+XEME_AVAILABLE_IN_0_1
+XemeTlsMode xeme_connection_get_tls_mode(XemeConnection *connection);
+
+/**
+ * xeme_connection_set_tls_mode:
+ * @connection: The instance.
+ * @tls_mode: The new TLS mode.
+ *
+ * Sets the [enum@TlsMode] of @connection to @tls_mode.
+ *
+ * Since: 0.1.0
+ */
+XEME_AVAILABLE_IN_0_1
+void xeme_connection_set_tls_mode(XemeConnection *connection, XemeTlsMode tls_mode);
+
+/**
+ * xeme_connection_connection_async:
+ * @connection: The instance.
+ * @input: The [class@InputStream] to use.
+ * @resolver: (transfer full) (nullable): An optional proxy resolver.
+ * @cancellable: (transfer none) (nullable): An optional cancellable.
+ * @callback: (scope async) (nullable): A callback function.
+ * @data: (nullable): User data pass to @callback.
+ *
+ * Starts the connection process.
+ *
+ * If [property@Connection:server] is not %NULL, then this will try to connect
+ * directly to that server on the port specified by [property@Connection:port].
+ *
+ * If [property@Connection:server] is %NULL then DNS SRV records will be used
+ * to connect per
+ * [RFC 6120](https://www.rfc-editor.org/rfc/rfc6120#section-3.2.4).
+ *
+ * If [property@Connection:tls-mode] is set to `direct-tls`, then the
+ * `_xmpps-client` service will be queried. If the DNS SRV lookup does not
+ * return a record, an attempt will be made to connect directly to the domain
+ * part of [property@Connection:jid] on the port specified by
+ * [property@Connection:port].
+ *
+ * If [property@Connection:tls-mode] is set to `starttls` or `none` then the
+ * `_xmpp-client` service will be queried. If the DNS SRV lookup does not
+ * return a record, an attempt will be made to connect directly to the domain
+ * part of [property@Connection:jid] on the port specified by
+ * [property@Connection:port].
+ *
+ * If [property@Connection:tls-mode] is set to `starttls` then the connection
+ * will attempt to upgrade to TLS during the connection process. If this fails,
+ * the connection will be terminated.
+ *
+ * Since: 0.1.0
+ */
+XEME_AVAILABLE_IN_0_1
+void xeme_connection_connect_async(XemeConnection *connection, XemeInputStream *input, GProxyResolver *resolver, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data);
+
+/**
+ * xeme_connection_connect_finish:
+ * @connection: The instance.
+ * @result: The result passed to the callback.
+ * @error: A return address for a #GError.
+ *
+ * Finishes a previous call to [method@Connection.connect_async].
+ *
+ * This should be call from the callback function of
+ * [method@Connection.connect_async] to get the result of the connection
+ * attempt.
+ *
+ * Returns: (transfer full): A new [class@OutputStream] or %NULL if the
+ * connection failed.
+ *
+ * Since: 0.1.0
+ */
+XEME_AVAILABLE_IN_0_1
+XemeOutputStream *xeme_connection_connect_finish(XemeConnection *connection, GAsyncResult *result, GError **error);
+
+/**
+ * xeme_connection_close:
+ * @connection: The instance.
+ * @error: (nullable): A return address for a #GError.
+ *
+ * Attempts to close the connection.
+ *
+ * Returns: %TRUE if sucessfull, otherwise %FALSE with @error possibly set.
+ *
+ * Since: 0.1.0
+ */
+XEME_AVAILABLE_IN_0_1
+gboolean xeme_connection_close(XemeConnection *connection, GError **error);
+
+G_END_DECLS
+
+#endif /* XEME_CONNECTION_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/xeme/xemeconstants.h Fri Dec 08 00:05:46 2023 -0600
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2023 Xeme Developers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef XEME_CONSTANTS_H
+#define XEME_CONSTANTS_H
+
+#include <xeme/xemeversion.h>
+
+/**
+ * XEME_PORT_CLEAR:
+ *
+ * A constant representing the default clear text port.
+ *
+ * Since: 0.1.0
+ */
+#define XEME_PORT_CLEAR (5222) XEME_AVAILABLE_MACRO_IN_0_1
+
+/**
+ * XEME_PORT_TLS:
+ *
+ * A constant representing the default TLS port.
+ *
+ * Since: 0.1.0
+ */
+#define XEME_PORT_TLS (5223) XEME_AVAILABLE_MACRO_IN_0_1
+
+/**
+ * XEME_SERVICE_XMPP_CLIENT:
+ *
+ * A constant representing the xmpp-client service DNS record for clear text
+ * connections.
+ *
+ * Since: 0.1.0
+ */
+#define XEME_SERVICE_XMPP_CLIENT ("xmpp-client") XEME_AVAILABLE_MACRO_IN_0_1
+
+/**
+ * XEME_SERVICE_XMPPS_CLIENT:
+ *
+ * A constant representing the xmpps-client service DNS record for TLS
+ * connections.
+ *
+ * Since: 0.1.0
+ */
+#define XEME_SERVICE_XMPPS_CLIENT ("xmpps-client") XEME_AVAILABLE_MACRO_IN_0_1
+
+#endif /* XEME_CONSTANTS_H */