首页 > 解决方案 > 两个用户之间的 DBUS 通信

问题描述

不幸的是,关于 dbus 通信的信息很少。有谁知道,如何在同一个linux上完成两个用户之间的通信?应该注意哪些事项?应该使用什么类型的 dbus(会话或系统)?

标签: dbus

解决方案


谢谢@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>

服务器.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);
}

生成文件

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

推荐阅读