Связь DBUS между двумя пользователями

К сожалению, очень мало информации о связи dbus. У кого-нибудь есть идея, как осуществить общение между двумя пользователями в одном и том же Linux? На какие вещи стоит обратить внимание? Какой тип dbus (сеанс или система) следует использовать?


person respect99    schedule 14.01.2021    source источник
comment
Что означает two users? Один работает как сервер, а другой как клиент? или вы имеете в виду две учетные записи пользователей Linux? Что касается типа dbus, сеансовая шина работает для одного пользовательского сеанса, а системная шина работает независимо от каких-либо пользовательских сеансов. Это зависит от того, чего вы пытаетесь достичь.   -  person Anton    schedule 16.01.2021
comment
Связь между двумя учетными записями пользователей Linux. Я хочу запустить сервер на одной учетной записи пользователя Linux и запустить клиент на другой учетной записи пользователя Linux, и в результате получить связь клиент-сервер между двумя учетными записями пользователей Linux.   -  person respect99    schedule 16.01.2021
comment
В этом случае службе необходимо запросить системную шину, поскольку вы собираетесь использовать две учетные записи пользователей Linux. На что вам нужно обратить внимание, так это то, что dbusconfig должен быть установлен/размещен под /etc/dbus-1/system.d/<bus-name>.conf и определить, какой пользователь может владеть шиной, какой пользователь может общаться с шиной, получать информацию от отправителя. Это отвечает на ваши вопросы? Я предполагаю, что у вас уже есть несколько клиент-серверных приложений, которые могут обмениваться данными через D-Bus.   -  person Anton    schedule 17.01.2021
comment
Спасибо, это мой вопрос.   -  person respect99    schedule 17.01.2021


Ответы (2)


Спасибо, @Anton, теперь я понимаю, что сессионная шина должна удовлетворять двум условиям: один и тот же uid и одна и та же сессионная шина. В данный момент пытаюсь установить связь между двумя пользователями через системную D-bus, но явно делаю не так.

/etc/dbus-1/system.d/test_bus.conf

<!DOCTYPE busconfig PUBLIC
 "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
 "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
        <policy user="user">
                <allow own="com.test.Bus"/>
                <allow send_destination="com.test.Bus"/>
                <allow send_interface="com.test.Bus"/>
                <allow receive_sender="com.test.Bus"/>
        </policy>
        <policy user="user2">
                <allow own="com.test.Bus"/>
                <allow send_destination="com.test.Bus"/>
                <allow send_interface="com.test.Bus"/>
                <allow receive_sender="com.test.Bus"/>
        </policy>
</busconfig>

server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <ctype.h>
#include <dbus/dbus.h>

const char* const INTERFACE_NAME = "com.test.Bus";
const char* const SERVER_BUS_NAME = "com.test.Bus";
const char* const OBJECT_PATH_NAME = "/server";
const char* const METHOD_NAME = "add_numbers";

DBusError dbus_error;
void      print_dbus_error(char* str);
bool      isinteger(char* ptr);

int main(int argc, char** argv)
{

    DBusConnection* conn;
    int             ret;

    dbus_error_init(&dbus_error);

    conn = dbus_bus_get(DBUS_BUS_SYSTEM, &dbus_error);
    printf("Con name=%s\n", dbus_bus_get_unique_name(conn)); // my

    if (dbus_error_is_set(&dbus_error))
        print_dbus_error("dbus_bus_get");

    if (!conn)
        exit(1);

    // Get a well known name
    ret = dbus_bus_request_name(conn, SERVER_BUS_NAME, DBUS_NAME_FLAG_DO_NOT_QUEUE, &dbus_error);

    if (dbus_error_is_set(&dbus_error))
        print_dbus_error("dbus_bus_get");

    if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
    {
        fprintf(stderr, "Dbus: not primary owner, ret = %d\n", ret);
        exit(1);
    }

    // Handle request from clients
    while (1)
    {
        // Block for msg from client
        if (!dbus_connection_read_write_dispatch(conn, -1))
        {
            fprintf(stderr, "Not connected now.\n");
            exit(1);
        }

        DBusMessage* message;

        if ((message = dbus_connection_pop_message(conn)) == NULL)
        {
            fprintf(stderr, "Did not get message\n");
            continue;
        }

        if (dbus_message_is_method_call(message, INTERFACE_NAME, METHOD_NAME))
        {
            char*      s;
            char *     str1 = NULL, *str2 = NULL;
            const char space[4] = " \n\t";
            long       i, j;
            bool       error = false;

            if (dbus_message_get_args(message, &dbus_error, DBUS_TYPE_STRING, &s, DBUS_TYPE_INVALID))
            {
                printf("%s", s);
                // Validate received message
                str1 = strtok(s, space);
                if (str1)
                    str2 = strtok(NULL, space);

                if (!str1 || !str2)
                    error = true;

                if (!error)
                {
                    if (isinteger(str1))
                        i = atol(str1);
                    else
                        error = true;
                }
                if (!error)
                {
                    if (isinteger(str2))
                        j = atol(str2);
                    else
                        error = true;
                }

                if (!error)
                {
                    // send reply
                    DBusMessage* reply;
                    char         answer[40];

                    sprintf(answer, "Sum is %ld", i + j);
                    if ((reply = dbus_message_new_method_return(message)) == NULL)
                    {
                        fprintf(stderr, "Error in dbus_message_new_method_return\n");
                        exit(1);
                    }

                    DBusMessageIter iter;
                    dbus_message_iter_init_append(reply, &iter);
                    char* ptr = answer;
                    if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &ptr))
                    {
                        fprintf(stderr, "Error in dbus_message_iter_append_basic\n");
                        exit(1);
                    }

                    if (!dbus_connection_send(conn, reply, NULL))
                    {
                        fprintf(stderr, "Error in dbus_connection_send\n");
                        exit(1);
                    }

                    dbus_connection_flush(conn);

                    dbus_message_unref(reply);
                }
                else // There was an error
                {
                    DBusMessage* dbus_error_msg;
                    char         error_msg[] = "Error in input";
                    if ((dbus_error_msg = dbus_message_new_error(message, DBUS_ERROR_FAILED, error_msg)) == NULL)
                    {
                        fprintf(stderr, "Error in dbus_message_new_error\n");
                        exit(1);
                    }

                    if (!dbus_connection_send(conn, dbus_error_msg, NULL))
                    {
                        fprintf(stderr, "Error in dbus_connection_send\n");
                        exit(1);
                    }

                    dbus_connection_flush(conn);

                    dbus_message_unref(dbus_error_msg);
                }
            }
            else
            {
                print_dbus_error("Error getting message");
            }
        }
    }

    return 0;
}

bool isinteger(char* ptr)
{
    if (*ptr == '+' || *ptr == '-')
        ptr++;

    while (*ptr)
    {
        if (!isdigit((int)*ptr++))
            return false;
    }

    return true;
}

void print_dbus_error(char* str)
{
    fprintf(stderr, "%s: %s\n", str, dbus_error.message);
    dbus_error_free(&dbus_error);
}

клиент.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdbool.h>
#include <ctype.h>

#include <dbus/dbus.h>

const char* const INTERFACE_NAME = "com.test.Bus";
const char* const SERVER_BUS_NAME = "com.test.Bus";
const char* const CLIENT_BUS_NAME = "com.test.Bus";
const char* const SERVER_OBJECT_PATH_NAME = "/server";
const char* const CLIENT_OBJECT_PATH_NAME = "/client";
const char* const METHOD_NAME = "add_numbers";

DBusError dbus_error;
void      print_dbus_error(char* str);

int main(int argc, char** argv)
{


    DBusConnection* conn;
    int             ret;
    char            input[80];

    dbus_error_init(&dbus_error);

    conn = dbus_bus_get(DBUS_BUS_SYSTEM, &dbus_error);

    printf("Con name=%s\n", dbus_bus_get_unique_name(conn)); // my

    if (dbus_error_is_set(&dbus_error))
        print_dbus_error("dbus_bus_get");

    if (!conn)
        exit(1);

    printf("Please type two numbers: ");
    while (fgets(input, 78, stdin) != NULL)
    {
        // Get a well known name
        while (1)
        {
            ret = dbus_bus_request_name(conn, CLIENT_BUS_NAME, 0, &dbus_error);

            if (ret == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
                break;

            if (ret == DBUS_REQUEST_NAME_REPLY_IN_QUEUE)
            {
                fprintf(stderr, "Waiting for the bus ... \n");
                sleep(1);
                continue;
            }
            if (dbus_error_is_set(&dbus_error))
                print_dbus_error("dbus_bus_get");
        }

        DBusMessage* request;

        if ((request = dbus_message_new_method_call(SERVER_BUS_NAME, SERVER_OBJECT_PATH_NAME, INTERFACE_NAME,
                                                    METHOD_NAME)) == NULL)
        {
            fprintf(stderr, "Error in dbus_message_new_method_call\n");
            exit(1);
        }

        DBusMessageIter iter;
        dbus_message_iter_init_append(request, &iter);
        char* ptr = input;
        if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &ptr))
        {
            fprintf(stderr, "Error in dbus_message_iter_append_basic\n");
            exit(1);
        }
        DBusPendingCall* pending_return;
        if (!dbus_connection_send_with_reply(conn, request, &pending_return, -1))
        {
            fprintf(stderr, "Error in dbus_connection_send_with_reply\n");
            exit(1);
        }

        if (pending_return == NULL)
        {
            fprintf(stderr, "pending return is NULL");
            exit(1);
        }

        dbus_connection_flush(conn);

        dbus_message_unref(request);

        dbus_pending_call_block(pending_return);

        DBusMessage* reply;
        if ((reply = dbus_pending_call_steal_reply(pending_return)) == NULL)
        {
            fprintf(stderr, "Error in dbus_pending_call_steal_reply");
            exit(1);
        }

        dbus_pending_call_unref(pending_return);

        char* s;
        if (dbus_message_get_args(reply, &dbus_error, DBUS_TYPE_STRING, &s, DBUS_TYPE_INVALID))
        {
            printf("%s\n", s);
        }
        else
        {
            fprintf(stderr, "Did not get arguments in reply\n");
            exit(1);
        }
        dbus_message_unref(reply);

        if (dbus_bus_release_name(conn, CLIENT_BUS_NAME, &dbus_error) == -1)
        {
            fprintf(stderr, "Error in dbus_bus_release_name\n");
            exit(1);
        }

        printf("Please type two numbers: ");
    }

    return 0;
}

void print_dbus_error(char* str)
{
    fprintf(stderr, "%s: %s\n", str, dbus_error.message);
    dbus_error_free(&dbus_error);
}

Makefile

all: serverDBUS clientDBUS

%.o: %.c
    gcc -Wall -c $< `pkg-config --cflags dbus-1`

serverDBUS: server.o
    gcc server.o -o serverDBUS `pkg-config --libs dbus-1`

clientDBUS: client.o
    gcc client.o -o clientDBUS `pkg-config --libs dbus-1`

.PHONY: clean
clean:
    rm *.o serverDBUS clientDBUS
person respect99    schedule 17.01.2021
comment
Это совсем другой вопрос. Я вижу, что вы никогда не вызываете dbus_connection_register_object_path для регистрации вашего интерфейса. Кроме того, взгляните на https://github.com/fbuihuu/samples-dbus/blob/master/dbus-server.c для справки. Я бы рекомендовал открыть новый вопрос, если вы все еще застряли. Я отвечу на ваш первоначальный вопрос, отметьте его принятым, чтобы не смущать других людей. - person Anton; 17.01.2021
comment
Еще один совет от меня: чтобы проверить, правильно ли ваш serverDBus предоставляет интерфейс, и вы также можете вызвать метод интерфейса, вы можете использовать инструмент под названием d-feet. Это более удобно для пользователя, чем использование dbus-send, по крайней мере, для людей, которые плохо знакомы с dbus. - person Anton; 17.01.2021

Если вы собираетесь использовать двух пользователей Linux для своего клиент-серверного приложения, службе необходимо запросить системную шину.

На что вам нужно обратить внимание, так это то, что dbusconfig должен быть установлен/размещен в /etc/dbus-1/system.d/your-bus-name.conf и определить, какой пользователь может владеть шиной, какой пользователь может общаться с шиной. , получить информацию от отправителя.

e.g.

<!DOCTYPE busconfig PUBLIC
          "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
          "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">

<!-- To be installed to /etc/dbus-1/system.d/com.test.DBus.conf so your service can own a system bus -->

<busconfig>
  <policy user="root">
    <allow own="com.test.DBus"/>
  </policy>
  <policy user="user">
    <allow own="com.test.DBus"/>
  </policy>

  <!-- Allow anyone to invoke methods to the interface -->
  <policy context="default">
    <allow send_destination="com.test.DBus"/>
    <allow receive_sender="com.test.DBus"/>
  </policy>
</busconfig>

Я предполагаю, что у вас уже есть несколько клиент-серверных приложений, которые могут обмениваться данными через D-Bus.

person Anton    schedule 17.01.2021