Files

399 lines
10 KiB
C++
Raw Permalink Normal View History

2026-09-22 09:38:26 +08:00
/*
* SPDX-License-Identifier: LicenseRef-Unisoc-General-1.0
* Copyright 2016-2023 Unisoc (Shanghai) Technologies Co., Ltd
* Licensed under the Unisoc General Software License, version 1.0 (the License);
* you may not use this file except in compliance with the License. You may obtain a copy of the License at
* https://www.unisoc.com/en_us/license/UNISOC_GENERAL_LICENSE_V1.0-EN_US
* Software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OF ANY KIND, either express or implied.
* See the Unisoc General Software License, version 1.0 for more details.
*/
#include <Debug.h>
#include <Connection.h>
#include <dbus/dbus.h>
#include <string>
#include "InternalError.h"
#include "ConnectionInternal.h"
#include "DispatcherInternal.h"
#include "MessageInternal.h"
#include "PendingcallInternal.h"
using namespace UDBus;
Connection::PrivateSuffix::PrivateSuffix(DBusBusType BusType)
:dispatcher(nullptr)
{
UDbusInternalError err;
Connection = dbus_bus_get_private(BusType, err);
if (err)
throw UDBusError(err);
InitSuffix();
}
Connection::PrivateSuffix::~PrivateSuffix()
{
if (dbus_connection_get_is_connected(Connection)) {
std::vector<std::string>::iterator s = VtNames.begin();
while (s != VtNames.end()) {
dbus_bus_release_name(Connection, s->c_str(), nullptr);
++s;
}
dbus_connection_close(Connection);
}
dbus_connection_unref(Connection);
}
void Connection::PrivateSuffix::InitSuffix()
{
DEBUG("");
dbus_connection_ref(Connection);
dbus_connection_ref(Connection); //todo: the library has to own another reference
disconnFilter = new Callback<Connection::PrivateSuffix, bool, const Message &>(this, &Connection::PrivateSuffix::DisconnFilterFunction);
if (!dbus_connection_add_filter(Connection, MessageFilterStub, &disconnFilter, nullptr))
{
dbus_connection_unref(Connection);
dbus_connection_unref(Connection);
throw ErrorFailed("dbus_connection_add_filter failed");
}
dbus_connection_set_dispatch_status_function(Connection, DispatchStatusStub, this, 0);
dbus_connection_set_exit_on_disconnect(Connection, false); //why was this set to true??
}
bool Connection::PrivateSuffix::DoDispatch()
{
if (!dbus_connection_get_is_connected(Connection)) {
return true;
}
return dbus_connection_dispatch(Connection) != DBUS_DISPATCH_DATA_REMAINS;
}
void Connection::PrivateSuffix::DispatchStatusStub(DBusConnection *dbuscon, DBusDispatchStatus status, void *data)
{
PrivateSuffix *ps = static_cast<PrivateSuffix *>(data);
switch (status) {
case DBUS_DISPATCH_DATA_REMAINS:
ps->dispatcher->QueueConnection(ps);
break;
case DBUS_DISPATCH_COMPLETE:
break;
case DBUS_DISPATCH_NEED_MEMORY: //uh oh...
break;
}
}
DBusHandlerResult Connection::PrivateSuffix::MessageFilterStub(DBusConnection *Connection, DBusMessage *dmsg, void *data_void)
{
MessageSlot *Msglot = static_cast<MessageSlot *>(data_void);
Message NewMsg = Message(new Message::UDBusPrivate(dmsg));
return Msglot && !Msglot->IsEmpty() && Msglot->Call(NewMsg)
? DBUS_HANDLER_RESULT_HANDLED
: DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
bool Connection::PrivateSuffix::DisconnFilterFunction(const Message &CMsg)
{
if (CMsg.IsSignal(DBUS_INTERFACE_LOCAL, "Disconnected")) {
dbus_connection_close(Connection);
return true;
}
return false;
}
DBusDispatchStatus Connection::PrivateSuffix::DispatchStatus()
{
return dbus_connection_get_dispatch_status(Connection);
}
bool Connection::PrivateSuffix::HasSomethingToDispatch()
{
return DispatchStatus() == DBUS_DISPATCH_DATA_REMAINS;
}
Connection Connection::SystemBus()
{
return Connection(new PrivateSuffix(DBUS_BUS_SYSTEM));
}
Connection Connection::SessionBus()
{
return Connection(new PrivateSuffix(DBUS_BUS_SESSION));
}
Connection Connection::ActivationBus()
{
return Connection(new PrivateSuffix(DBUS_BUS_STARTER));
}
Connection::Connection(Connection::PrivateSuffix *p)
: mPrivate(p), mTimeout(-1)
{
Setup(gDefaultDispatcher);
}
Connection::Connection(const Connection &c)
: mPrivate(c.mPrivate), mTimeout(c.mTimeout)
{
dbus_connection_ref(mPrivate->Connection);
}
Connection::~Connection()
{
dbus_connection_unref(mPrivate->Connection);
}
Dispatcher *Connection::Setup(Dispatcher *dispatcher)
{
if (!dispatcher) dispatcher = gDefaultDispatcher;
if (!dispatcher) throw ErrorFailed("no default dispatcher set for new connection");
mPrivate->dispatcher = dispatcher;
dispatcher->QueueConnection(mPrivate.Get());
dbus_connection_set_watch_functions(
mPrivate->Connection,
Dispatcher::UDBusPrivate::OnAddWatch,
Dispatcher::UDBusPrivate::OnRemoveWatch,
Dispatcher::UDBusPrivate::OnToggleWatch,
dispatcher,
nullptr
);
dbus_connection_set_timeout_functions(
mPrivate->Connection,
Dispatcher::UDBusPrivate::OnAddTimeout,
Dispatcher::UDBusPrivate::OnRemTimeout,
Dispatcher::UDBusPrivate::OnToggleTimeout,
dispatcher,
nullptr
);
return dispatcher;
}
bool Connection::operator == (const Connection &c) const
{
return mPrivate->Connection == c.mPrivate->Connection;
}
bool Connection::RegisterBus()
{
UDbusInternalError e;
bool r = dbus_bus_register(mPrivate->Connection, e);
if (e) throw (e);
return r;
}
bool Connection::Connected() const
{
return dbus_connection_get_is_connected(mPrivate->Connection);
}
void Connection::Disconnect()
{
dbus_connection_close(mPrivate->Connection);
}
void Connection::ExitOnDisconnect(bool exit)
{
dbus_connection_set_exit_on_disconnect(mPrivate->Connection, exit);
}
bool Connection::UniqueName(const char *n)
{
return dbus_bus_set_unique_name(mPrivate->Connection, n);
}
const char *Connection::UniqueName() const
{
return dbus_bus_get_unique_name(mPrivate->Connection);
}
void Connection::Flush()
{
dbus_connection_flush(mPrivate->Connection);
}
void Connection::AddMatch(const char *rule)
{
UDbusInternalError e;
dbus_bus_add_match(mPrivate->Connection, rule, e);
if (e) throw UDBusError(e);
DEBUG("%s: added match rule %s", UniqueName(), rule);
}
void Connection::RmoveMatch(const char *rule)
{
UDbusInternalError e;
dbus_bus_remove_match(mPrivate->Connection, rule, e);
DEBUG("%s: removed match rule %s", UniqueName(), rule);
if (e) throw UDBusError(e);
}
bool Connection::AddFilter(MessageSlot &s)
{
DEBUG("%s: adding filter", UniqueName());
return dbus_connection_add_filter(mPrivate->Connection, PrivateSuffix::MessageFilterStub, &s, nullptr);
}
void Connection::RemoveFilter(MessageSlot &s)
{
DEBUG("%s: removing filter", UniqueName());
dbus_connection_remove_filter(mPrivate->Connection, PrivateSuffix::MessageFilterStub, &s);
}
bool Connection::Send(const Message &cmsg, unsigned int *serial)
{
return dbus_connection_send(mPrivate->Connection, cmsg.mPrivate->msg, serial);
}
Message Connection::SendBlocking(Message &cmsg, int Timeout_ms)
{
DBusMessage *DBusreply;
UDbusInternalError error;
if (this->mTimeout != -1) {
DBusreply = dbus_connection_send_with_reply_and_block(mPrivate->Connection, cmsg.mPrivate->msg, this->mTimeout, error);
} else {
DBusreply = dbus_connection_send_with_reply_and_block(mPrivate->Connection, cmsg.mPrivate->msg, Timeout_ms, error);
}
if (error) throw UDBusError(error);
return Message(new Message::UDBusPrivate(DBusreply), false);
}
PendingCall *Connection::SendAsync(Message &Sendmsg, int Timeout_ms)
{
DBusPendingCall *DBusPending;
if (!dbus_connection_send_with_reply(mPrivate->Connection, Sendmsg.mPrivate->msg, &DBusPending, Timeout_ms)) {
throw ErrorNoMemory("Unable to start asynchronous call");
}
if (!DBusPending)
throw ErrorNoMemory("Unable to start asynchronous call");
return new PendingCall(new PendingCall::UDBusPrivate(DBusPending));
}
int Connection::RequestNameInternal(const char *charName, int intFlags)
{
UDbusInternalError error;
int returnNum = dbus_bus_request_name(mPrivate->Connection, charName, intFlags, error);
if (returnNum == -1) {
if (error) throw UDBusError(error);
}
if (charName) {
mPrivate->VtNames.push_back(charName);
std::string match = "destination='" + mPrivate->VtNames.back() + "'";
AddMatch(match.c_str());
}
return returnNum;
}
void Connection::RequestName(const char *name, int flags)
{
RequestNameInternal(name, flags);
}
bool Connection::AcquireName(const char *name)
{
int ret = RequestNameInternal(name, 0);
switch (ret) {
case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
return true;
case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
break;
case DBUS_REQUEST_NAME_REPLY_EXISTS:
default:
break;
}
CallMessage ping_request(name, "/", "smartlink.netcon.UDBus.Peer", "Ping");
try {
SendBlocking(ping_request, DBUS_TIMEOUT_USE_DEFAULT);
} catch (const UDBus::UDBusError &e) {
ERROR("%s", e.what());
}
ret = RequestNameInternal(name, DBUS_NAME_FLAG_DO_NOT_QUEUE);
switch (ret) {
case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
return true;
case DBUS_REQUEST_NAME_REPLY_EXISTS:
return false;
case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
default:
ERROR("%s %d", dbus_bus_get_unique_name(mPrivate->Connection), ret);
return false;
}
}
unsigned long Connection::SenderUnixUid(const char *sender)
{
UDbusInternalError e;
unsigned long ul = dbus_bus_get_unix_user(mPrivate->Connection, sender, e);
if (e) throw UDBusError(e);
return ul;
}
bool Connection::HasName(const char *name)
{
UDbusInternalError e;
bool b = dbus_bus_name_has_owner(mPrivate->Connection, name, e);
if (e) throw UDBusError(e);
return b;
}
const std::vector<std::string> &Connection::names()
{
return mPrivate->VtNames;
}
bool Connection::StartService(const char *name, unsigned long flags)
{
UDbusInternalError e;
bool b = dbus_bus_start_service_by_name(mPrivate->Connection, name, flags, nullptr, e);
if (e) throw UDBusError(e);
return b;
}
void Connection::SetTimeout(int Timeout_ms)
{
mTimeout = Timeout_ms;
}
int Connection::GetTimeout()
{
return mTimeout;
}