Как создать прямое соединение dbus, используя UNIX ДОМЕННАЯ РОЗЕТКА? - PullRequest
1 голос
/ 11 февраля 2020

Пожалуйста, поймите, что я плохо разбираюсь в английском sh.

В настоящее время я создаю тест, включающий сервер и клиент, которые общаются через соединение dbus без демона D-Bus (я не уверен, что это правильная формулировка) в своем собственном процессе. И используемый sd-bus API.

  1. есть серверный процесс, выполняющий сервер dbus (sdbus)

    • сервер создает unix доменный сокет для связи и устанавливает информацию о сокете на шину
    • использовать путь к сокету, а не сокет fd (например, sd_bus_set_address)
  2. есть клиентский процесс, выполняющий sdbus

    • клиент использует unix путь к сокету домена для установления соединения

на стороне сервера

server::server(const char *path, const char *description)
: bus_(nullptr),
  path_(path)
{
         // create socket  
    auto tmpfd =  socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
    struct sockaddr_un addr, claddr;
    bzero(&addr, sizeof(addr));
    bzero(&claddr, sizeof(claddr));
    addr.sun_family = AF_UNIX;
    unlink(path);
    strcpy(addr.sun_path, path);
    auto state = bind(tmpfd, (struct sockaddr*)&addr, sizeof(addr));
    state = listen(tmpfd, SOMAXCONN);
         // socket created

  socklen_t leng;
  // wait for client side connection
  auto FD = accept4( tmpfd, (struct sockaddr*) &claddr, &leng, SOCK_NONBLOCK|SOCK_CLOEXEC);

  sd_id128_t id;
  auto ret = sd_id128_randomize(&id);
  assert( ret >= 0 );

  ret = sd_bus_new(&bus_);
  assert(ret>=0);

// using path like connection seems fine but doesn't work
/*  std::string unixpath = "unix:path=";
    unixpath += path;

    ret = sd_bus_set_address(bus_, unixpath.c_str());*/

    // use client side fd 
    ret = sd_bus_set_fd(bus_, FD, FD);
    assert(ret>=0);
    ret = sd_bus_set_server( bus_, 1, id);
    assert(ret>=0);

    ret = sd_bus_start(bus_);
    assert(ret>=0);

    // failed to get address
    const char * servaddr;
    ret = sd_bus_get_address(bus_, &servaddr);

  while(1) {
    // check sd-bus work if it has
    sleep(1);
    dostuff();
  }
}

void server::dostuff() {

  sd_bus_message *m{nullptr}, *reply{nullptr};
  auto ret = sd_bus_process(bus_, &m);

  if( ret > 0 ) {

    const char * str = sd_bus_message_get_member(m);

    ret = sd_bus_message_is_method_call(m, "org.freedesktop.systemd.test", "Exit"); 

    if( ret >=0 ) {
        ret = sd_bus_message_new_method_return(m, &reply);
        std::cout << "method call" << std::endl;
      }
    }
}


на стороне клиента

client::client( const char* path, const char* description )
: bus_(nullptr),
  path_(path)
{
  auto ret = sd_bus_new(&bus_);
  assert(ret>=0);

  ret = sd_bus_set_description( bus_, description );
  assert(ret>=0);

  std::string unixpath = "unix:path=";
  unixpath += path;

  ret = sd_bus_set_address(bus_, unixpath.c_str());
  assert(ret>=0);

  ret = sd_bus_set_watch_bind( bus_, true);

  ret = sd_bus_start(bus_);
  assert(ret>=0);
}


void client::callA() {

  sd_bus_message *m{nullptr},  *reply{nullptr};
  sd_bus_error error{};

  auto ret = sd_bus_message_new_method_call(
            bus_,
            &m,
            "org.freedesktop.systemd.test",
            "/",
            "org.freedesktop.systemd.test",
            "Exit");

  assert(ret>=0);

  ret = sd_bus_call(bus_, m, 0, &error, &reply);
  assert(ret>=0);
}

этот код имеет несколько проблем. слишком сложно, чем то, что он делает сторона сервера должна ждать, пока сторона клиента не установит соединение на стороне сервера есть странное ожидание соединения на стороне клиента и создание sd-шины с этим fd снова и снова Протокол метода d-bus не работает после создания соединения

Ниже приведены примеры кодов sd-шины, о которых я говорил. https://github.com/systemd/systemd/blob/1788875576b70ddd19aaf8199dca6691f4105a0b/src/libsystemd/sd-bus/test-bus-watch-bind.c https://github.com/systemd/systemd/blob/1788875576b70ddd19aaf8199dca6691f4105a0b/src/libsystemd/sd-bus/test-bus-chat.c https://github.com/systemd/systemd/blob/1788875576b70ddd19aaf8199dca6691f4105a0b/src/libsystemd/sd-bus/test-bus-server.c

На самом деле, пример кода предпочитает соединение с использованием fd с API-интерфейсом socketpair, а не путем к сокету. Я думаю, что вопрос ниже имеет ту же проблему, но тестовый код просто использовать сокет FD. https://www.spinics.net/lists/systemd-devel/msg01563.html

То, что я хочу, это создать прямое соединение dbus, используя путь к сокету, так же просто, как при использовании сокета fd, без ожидания клиента (accept4 api на стороне сервера).

На gdbus это легко. но я не могу использовать из-за проблемы с лицензией.

//create server
g_dbus_server_new_sync();

// address to access server at client side
g_dbus_server_get_client_address();

Подводя итог, я хочу Установите прямое dbus-соединение между процессами без dbus-daemon Используйте путь к сокету домена, а не сокет fd для установления соединения. Не ждите подключения на стороне клиента, как «accpet4» API

Есть ли какой-нибудь код прорыва или пример с d-bus или sd-bus? Извините за зашифрованные абзацы снова Спасибо за чтение.

...