summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TelepathyQt/pending-dbus-tube-connection.cpp1
-rw-r--r--tests/dbus/dbus-tube-chan.cpp22
-rw-r--r--tests/lib/glib/CMakeLists.txt3
-rw-r--r--tests/lib/glib/dbus-tube-chan.c276
4 files changed, 271 insertions, 31 deletions
diff --git a/TelepathyQt/pending-dbus-tube-connection.cpp b/TelepathyQt/pending-dbus-tube-connection.cpp
index d71fd57e..b8f9d3d3 100644
--- a/TelepathyQt/pending-dbus-tube-connection.cpp
+++ b/TelepathyQt/pending-dbus-tube-connection.cpp
@@ -168,6 +168,7 @@ void PendingDBusTubeConnection::onConnectionFinished(PendingOperation *op)
// Now get the address and set it
PendingString *ps = qobject_cast<PendingString*>(op);
+ debug() << "Got address " << ps->result();
mPriv->tube->setAddress(ps->result());
// It might have been already opened - check
diff --git a/tests/dbus/dbus-tube-chan.cpp b/tests/dbus/dbus-tube-chan.cpp
index abc4fc6c..24427c23 100644
--- a/tests/dbus/dbus-tube-chan.cpp
+++ b/tests/dbus/dbus-tube-chan.cpp
@@ -131,6 +131,7 @@ private:
void TestDBusTubeChan::onBusNamesChanged(const QHash<ContactPtr, QString> &added,
const QList<ContactPtr> &removed)
{
+ qDebug() << "Bus names changed!";
for (QHash<ContactPtr, QString>::const_iterator i = added.constBegin();
i != added.constEnd(); ++i) {
mCurrentBusNames.insert(i.key(), i.value());
@@ -391,33 +392,14 @@ void TestDBusTubeChan::testAcceptSuccess()
QDBusConnection conn(QLatin1String("tmp"));
- if (contexts[i].withContact) {
- conn = QDBusConnection::connectToPeer(mChan->address(), mChan->serviceName());
- } else {
- conn = QDBusConnection::connectToBus(mChan->address(), mChan->serviceName());
- }
+ conn = QDBusConnection::connectToPeer(mChan->address(), mChan->serviceName());
-// if (requiresCredentials) {
-// qDebug() << "Sending credential byte" << mCredentialByte;
-// socket->write(reinterpret_cast<const char*>(&mCredentialByte), 1);
-// }
-
- QCOMPARE(mLoop->exec(), 0);
QCOMPARE(conn.isConnected(), true);
qDebug() << "Connected to host";
} else {
QVERIFY(false);
}
-// mGotConnectionClosed = false;
-// QVERIFY(connect(mChan.data(),
-// SIGNAL(connectionClosed(uint,QString,QString)),
-// SLOT(onConnectionClosed(uint,QString,QString))));
-// tp_tests_dbus_tube_channel_last_connection_disconnected(mChanService,
-// TP_ERROR_STR_DISCONNECTED);
-// QCOMPARE(mLoop->exec(), 0);
-// QCOMPARE(mGotConnectionClosed, true);
-
/* as we run several tests here, let's init/cleanup properly */
cleanup();
}
diff --git a/tests/lib/glib/CMakeLists.txt b/tests/lib/glib/CMakeLists.txt
index 0b0a4cad..915f0df7 100644
--- a/tests/lib/glib/CMakeLists.txt
+++ b/tests/lib/glib/CMakeLists.txt
@@ -5,7 +5,8 @@ include_directories(
${GOBJECT_INCLUDE_DIR}
${GIO_INCLUDE_DIR}
${GIOUNIX_INCLUDE_DIR}
- ${DBUS_INCLUDE_DIR})
+ ${DBUS_INCLUDE_DIR}
+ ${DBUS_ARCH_INCLUDE_DIR})
if(ENABLE_TP_GLIB_TESTS)
add_subdirectory(call)
diff --git a/tests/lib/glib/dbus-tube-chan.c b/tests/lib/glib/dbus-tube-chan.c
index e0cd80a5..43b0cacc 100644
--- a/tests/lib/glib/dbus-tube-chan.c
+++ b/tests/lib/glib/dbus-tube-chan.c
@@ -15,6 +15,9 @@
#include <telepathy-glib/svc-channel.h>
#include <telepathy-glib/gnio-util.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
#include <gio/gunixsocketaddress.h>
#include <gio/gunixconnection.h>
@@ -27,13 +30,38 @@ enum
PROP_SUPPORTED_ACCESS_CONTROLS,
PROP_PARAMETERS,
PROP_STATE,
+ PROP_DBUS_ADDRESS
};
struct _TpTestsDBusTubeChannelPrivate {
TpTubeChannelState state;
- /* TpHandle -> gchar * */
+ TpSocketAccessControl access_control;
+
+ /* our unique D-Bus name on the virtual tube bus (NULL for 1-1 D-Bus tubes)*/
+ gchar *dbus_local_name;
+ /* the address that we are listening for D-Bus connections on */
+ gchar *dbus_srv_addr;
+ /* the path of the UNIX socket used by the D-Bus server */
+ gchar *socket_path;
+ /* the server that's listening on dbus_srv_addr */
+ DBusServer *dbus_srv;
+ /* the connection to dbus_srv from a local client, or NULL */
+ DBusConnection *dbus_conn;
+ /* the queue of D-Bus messages to be delivered to a local client when it
+ * will connect */
+ GSList *dbus_msg_queue;
+ /* current size of the queue in bytes. The maximum is MAX_QUEUE_SIZE */
+ unsigned long dbus_msg_queue_size;
+ /* mapping of contact handle -> D-Bus name (empty for 1-1 D-Bus tubes) */
GHashTable *dbus_names;
+ /* mapping of D-Bus name -> contact handle */
+ GHashTable *dbus_name_to_handle;
+
+ /* Message reassembly buffer (CONTACT tubes only) */
+ GString *reassembly_buffer;
+ /* Number of bytes that will be in the next message, 0 if unknown */
+ guint32 reassembly_bytes_needed;
GArray *supported_access_controls;
@@ -68,6 +96,10 @@ tp_tests_dbus_tube_channel_get_property (GObject *object,
g_value_set_boxed (value, self->priv->parameters);
break;
+ case PROP_DBUS_ADDRESS:
+ g_value_set_string (value, self->priv->dbus_srv_addr);
+ break;
+
case PROP_STATE:
g_value_set_uint (value, self->priv->state);
break;
@@ -267,6 +299,15 @@ tp_tests_dbus_tube_channel_class_init (TpTestsDBusTubeChannelClass *klass)
g_object_class_install_property (object_class,
PROP_SUPPORTED_ACCESS_CONTROLS, param_spec);
+ param_spec = g_param_spec_string (
+ "dbus-address",
+ "D-Bus address",
+ "The D-Bus address on which this tube will listen for connections",
+ "",
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (object_class, PROP_DBUS_ADDRESS,
+ param_spec);
+
param_spec = g_param_spec_boxed (
"parameters", "Parameters",
"parameters of the tube",
@@ -321,6 +362,225 @@ change_state (TpTestsDBusTubeChannel *self,
tp_svc_channel_interface_tube_emit_tube_channel_state_changed (self, state);
}
+/*
+ * Characters used are permissible both in filenames and in D-Bus names. (See
+ * D-Bus specification for restrictions.)
+ */
+static void
+generate_ascii_string (guint len,
+ gchar *buf)
+{
+ const gchar *chars =
+ "0123456789"
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "_-";
+ guint i;
+
+ for (i = 0; i < len; i++)
+ buf[i] = chars[g_random_int_range (0, 64)];
+}
+
+static DBusHandlerResult
+filter_cb (DBusConnection *conn,
+ DBusMessage *msg,
+ void *user_data)
+{
+ TpTestsDBusTubeChannel *self = TP_TESTS_DBUS_TUBE_CHANNEL (user_data);
+ TpTestsDBusTubeChannelPrivate *priv = self->priv;
+ gchar *marshalled = NULL;
+ gint len;
+
+ if (dbus_message_get_type (msg) == DBUS_MESSAGE_TYPE_SIGNAL &&
+ !tp_strdiff (dbus_message_get_interface (msg),
+ "org.freedesktop.DBus.Local") &&
+ !tp_strdiff (dbus_message_get_member (msg), "Disconnected"))
+ {
+ /* connection was disconnected */
+ g_debug ("connection was disconnected");
+ dbus_connection_close (priv->dbus_conn);
+ tp_clear_pointer (&priv->dbus_conn, dbus_connection_unref);
+ goto out;
+ }
+
+ if (priv->dbus_local_name != NULL)
+ {
+ if (!dbus_message_set_sender (msg, priv->dbus_local_name))
+ g_debug ("dbus_message_set_sender failed");
+ }
+
+ if (!dbus_message_marshal (msg, &marshalled, &len))
+ goto out;
+
+// if (GABBLE_IS_BYTESTREAM_MUC (priv->bytestream))
+// {
+// /* This bytestream support direct send */
+// const gchar *dest;
+//
+// dest = dbus_message_get_destination (msg);
+//
+// if (dest != NULL)
+// {
+// TpHandle handle;
+//
+// handle = GPOINTER_TO_UINT (g_hash_table_lookup (
+// priv->dbus_name_to_handle, dest));
+//
+// if (handle == 0)
+// {
+// g_debug ("Unknown D-Bus name: %s", dest);
+// goto out;
+// }
+//
+// gabble_bytestream_muc_send_to (
+// GABBLE_BYTESTREAM_MUC (priv->bytestream), handle, len,
+// marshalled);
+//
+// goto out;
+// }
+// }
+//
+// gabble_bytestream_iface_send (priv->bytestream, len, marshalled);
+
+out:
+ if (marshalled != NULL)
+ g_free (marshalled);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static dbus_bool_t
+allow_all_connections (DBusConnection *conn,
+ unsigned long uid,
+ void *data)
+{
+ return TRUE;
+}
+
+static void
+new_connection_cb (DBusServer *server,
+ DBusConnection *conn,
+ void *data)
+{
+ TpTestsDBusTubeChannel *self = TP_TESTS_DBUS_TUBE_CHANNEL (data);
+ TpTestsDBusTubeChannelPrivate *priv = self->priv;
+ guint32 serial;
+ GSList *i;
+
+ g_debug("lol new conn");
+
+ if (priv->dbus_conn != NULL)
+ /* we already have a connection; drop this new one */
+ /* return without reffing conn means it will be dropped */
+ return;
+
+ g_debug ("got connection");
+
+ dbus_connection_ref (conn);
+ dbus_connection_setup_with_g_main (conn, NULL);
+ dbus_connection_add_filter (conn, filter_cb, self, NULL);
+ priv->dbus_conn = conn;
+
+ if (priv->access_control == TP_SOCKET_ACCESS_CONTROL_LOCALHOST)
+ {
+ /* By default libdbus use Credentials access control. If user wants
+ * to use the Localhost access control, we need to bypass this check. */
+ dbus_connection_set_unix_user_function (conn, allow_all_connections,
+ NULL, NULL);
+ }
+
+ /* We may have received messages to deliver before the local connection is
+ * established. Theses messages are kept in the dbus_msg_queue list and are
+ * delivered as soon as we get the connection. */
+ g_debug ("%u messages in the queue (%lu bytes)",
+ g_slist_length (priv->dbus_msg_queue), priv->dbus_msg_queue_size);
+ priv->dbus_msg_queue = g_slist_reverse (priv->dbus_msg_queue);
+ for (i = priv->dbus_msg_queue; i != NULL; i = g_slist_delete_link (i, i))
+ {
+ DBusMessage *msg = i->data;
+ g_debug ("delivering queued message from '%s' to '%s' on the "
+ "new connection",
+ dbus_message_get_sender (msg),
+ dbus_message_get_destination (msg));
+ dbus_connection_send (priv->dbus_conn, msg, &serial);
+ dbus_message_unref (msg);
+ }
+ priv->dbus_msg_queue = NULL;
+ priv->dbus_msg_queue_size = 0;
+}
+
+/* There is two step to enable receiving a D-Bus connection from the local
+ * application:
+ * - listen on the socket
+ * - add the socket in the mainloop
+ *
+ * We need to know the socket path to return from the AcceptDBusTube D-Bus
+ * call but the socket in the mainloop must be added only when we are ready
+ * to receive connections, that is when the bytestream is fully open with the
+ * remote contact.
+ *
+ * See also Bug 13891:
+ * https://bugs.freedesktop.org/show_bug.cgi?id=13891
+ * */
+static gboolean
+create_dbus_server (TpTestsDBusTubeChannel *self,
+ GError **err)
+{
+#define SERVER_LISTEN_MAX_TRIES 5
+ TpTestsDBusTubeChannelPrivate *priv = self->priv;
+ guint i;
+
+ if (priv->dbus_srv != NULL)
+ return TRUE;
+
+ for (i = 0; i < SERVER_LISTEN_MAX_TRIES; i++)
+ {
+ gchar suffix[8];
+ DBusError error;
+
+ g_free (priv->dbus_srv_addr);
+ g_free (priv->socket_path);
+
+ generate_ascii_string (8, suffix);
+ priv->socket_path = g_strdup_printf ("%s/dbus-tpqt4-test-%.8s",
+ g_get_tmp_dir (), suffix);
+ priv->dbus_srv_addr = g_strdup_printf ("unix:path=%s",
+ priv->socket_path);
+
+ dbus_error_init (&error);
+ priv->dbus_srv = dbus_server_listen (priv->dbus_srv_addr, &error);
+
+ if (priv->dbus_srv != NULL)
+ break;
+
+ g_debug ("dbus_server_listen failed (try %u): %s: %s", i, error.name,
+ error.message);
+ dbus_error_free (&error);
+ }
+
+ if (priv->dbus_srv == NULL)
+ {
+ g_debug ("all attempts failed. Close the tube");
+
+ g_free (priv->dbus_srv_addr);
+ priv->dbus_srv_addr = NULL;
+
+ g_free (priv->socket_path);
+ priv->socket_path = NULL;
+
+ g_set_error (err, TP_ERRORS, TP_ERROR_NOT_AVAILABLE,
+ "Can't create D-Bus server");
+ return FALSE;
+ }
+
+ g_debug ("listening on %s", priv->dbus_srv_addr);
+
+ dbus_server_set_new_connection_function (priv->dbus_srv, new_connection_cb,
+ self, NULL);
+
+ return TRUE;
+}
+
static void
dbus_tube_offer (TpSvcChannelTypeDBusTube *iface,
GHashTable *parameters,
@@ -344,6 +604,8 @@ dbus_tube_offer (TpSvcChannelTypeDBusTube *iface,
goto fail;
}
+ self->priv->access_control = access_control;
+
// self->priv->address_type = address_type;
// self->priv->address = tp_g_value_slice_dup (address);
// self->priv->access_control = access_control;
@@ -367,7 +629,6 @@ dbus_tube_accept (TpSvcChannelTypeDBusTube *iface,
{
TpTestsDBusTubeChannel *self = (TpTestsDBusTubeChannel *) iface;
GError *error = NULL;
- gchar *address = NULL;
if (self->priv->state != TP_TUBE_CHANNEL_STATE_LOCAL_PENDING)
{
@@ -389,17 +650,12 @@ dbus_tube_accept (TpSvcChannelTypeDBusTube *iface,
return;
}
-// address = create_local_socket (self, address_type, access_control, &error);
-//
-// self->priv->access_control = access_control;
-// self->priv->access_control_param = tp_g_value_slice_dup (
-// access_control_param);
+ if (!create_dbus_server (self, &error))
+ goto fail;
change_state (self, TP_TUBE_CHANNEL_STATE_OPEN);
- tp_svc_channel_type_dbus_tube_return_from_accept (context, address);
-
- g_free (address);
+ tp_svc_channel_type_dbus_tube_return_from_accept (context, self->priv->dbus_srv_addr);
return;
fail: