К сожалению, очень мало информации о связи dbus. У кого-нибудь есть идея, как осуществить общение между двумя пользователями в одном и том же Linux? На какие вещи стоит обратить внимание? Какой тип dbus (сеанс или система) следует использовать?
Связь DBUS между двумя пользователями
Ответы (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
dbus_connection_register_object_path
для регистрации вашего интерфейса. Кроме того, взгляните на https://github.com/fbuihuu/samples-dbus/blob/master/dbus-server.c
для справки. Я бы рекомендовал открыть новый вопрос, если вы все еще застряли. Я отвечу на ваш первоначальный вопрос, отметьте его принятым, чтобы не смущать других людей.
- person Anton; 17.01.2021
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.
two users
? Один работает как сервер, а другой как клиент? или вы имеете в виду две учетные записи пользователей Linux? Что касается типа dbus, сеансовая шина работает для одного пользовательского сеанса, а системная шина работает независимо от каких-либо пользовательских сеансов. Это зависит от того, чего вы пытаетесь достичь. - person Anton   schedule 16.01.2021/etc/dbus-1/system.d/<bus-name>.conf
и определить, какой пользователь может владеть шиной, какой пользователь может общаться с шиной, получать информацию от отправителя. Это отвечает на ваши вопросы? Я предполагаю, что у вас уже есть несколько клиент-серверных приложений, которые могут обмениваться данными через D-Bus. - person Anton   schedule 17.01.2021