Skip to content

D-Bus: Get peer-to-peer connection via unix sockets to work #1585

@sdroege

Description

@sdroege

Discussed in #1583

Originally posted by sophie-h November 30, 2024
I have the following example code. It spawns a D-Bus server and client in the same binary. At the end there is a function call from the client. Instead of triggering the debug print in the server, the function call is timing out.

I have no clue what I'm doing wrong. I also tried to create a proxy, but that's also timing out.

I also tried the new server code from 17db771 but that also didn't made a difference. The function call still timed out. I also wrote a complete _sync based version of everything. The function call still timed out.

Help would be much appreciated.

use gio::{
    glib::{self, ExitCode, VariantTy},
    prelude::SocketExt,
    DBusConnectionFlags, DBusNodeInfo, Socket,
};
use std::os::{fd::IntoRawFd, unix::net::UnixStream};

use gio::prelude::*;

const EXAMPLE_XML: &str = r#"
  <node>
    <interface name='org.gnome.glycin'>
      <method name='Hello'>
        <arg type='s' name='name' direction='in'/>
        <arg type='s' name='greet' direction='out'/>
      </method>
    </interface>
  </node>
"#;

pub fn main() -> ExitCode {
    let app = gio::Application::builder()
        .application_id("com.example.app")
        .build();
    let _guard = app.hold();

    app.connect_startup(move |_app| {
        let (x, y) = std::os::unix::net::UnixStream::pair().unwrap();

        x.set_nonblocking(true).unwrap();
        y.set_nonblocking(true).unwrap();

        glib::spawn_future_local(spawn_server(x));
        glib::spawn_future_local(spawn_client(y));
    });

    app.connect_activate(move |_| {
        println!("Waiting for DBus Hello method to be called.");
    });

    app.run()
}

pub async fn spawn_server(fd: UnixStream) {
    let socket = unsafe { Socket::from_fd(fd.into_raw_fd()) }.unwrap();
    let socket_connection = socket.connection_factory_create_connection();

    let guid = gio::dbus_generate_guid();

    dbg!("server connecting");

    let connection = gio::DBusConnection::new_future(
        &socket_connection,
        Some(&guid),
        DBusConnectionFlags::AUTHENTICATION_SERVER
            .union(DBusConnectionFlags::DELAY_MESSAGE_PROCESSING),
        None,
    )
    .await
    .unwrap();

    dbg!("server connected");

    let interface_info = DBusNodeInfo::for_xml(EXAMPLE_XML)
        .unwrap()
        .lookup_interface("org.gnome.glycin")
        .unwrap();

    let _id = connection
        .register_object("/org/gnome/glycin", &interface_info)
        .method_call(|_connection, y, z, a, b, c, d| {
            dbg!(y, z, a, b, c, d);
        })
        .build()
        .unwrap();

    dbg!("server awaiting calls");

    std::mem::forget(connection);
}

pub async fn spawn_client(fd: UnixStream) {
    let socket_client = unsafe { Socket::from_fd(fd.into_raw_fd()) }.unwrap();
    let socket_connection_client = socket_client.connection_factory_create_connection();

    dbg!("client connecting");

    let connection = gio::DBusConnection::new_future(
        &socket_connection_client,
        None,
        DBusConnectionFlags::AUTHENTICATION_CLIENT
            .union(DBusConnectionFlags::DELAY_MESSAGE_PROCESSING),
        None,
    )
    .await
    .unwrap();

    dbg!("client connected");

    let result = connection
        .call_future(
            None,
            "/org/gnome/glycin",
            "org.gnome.glycin",
            "Hello",
            Some(&("x",).into()),
            Some(VariantTy::STRING),
            gio::DBusCallFlags::NONE,
            2000,
        )
        .await
        .unwrap();

    dbg!(result);
}
```</div>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions