Files
BPI-M2C/source_sync_rls_25c/source/unisoc/perflink/libudbus/Object.cpp
T

503 lines
14 KiB
C++
Raw 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 <Object.h>
#include "InternalError.h"
#include <cstring>
#include <map>
#include <dbus/dbus.h>
#include "MessageInternal.h"
#include "ConnectionInternal.h"
using namespace UDBus;
Object::Object(Connection &conn, const UDBus::Path &path, const char *service)
: mConn(conn),
mPath(path),
mService(service ? service : "")
{
}
Object::~Object()
{
}
struct UDbusObjectAdaptor::UDBusPrivate {
static void FuncStub_UnRegister(DBusConnection *, void *);
static DBusHandlerResult FuncStub_Message(DBusConnection *, DBusMessage *, void *);
};
static DBusObjectPathVTable _vtable = {
UDbusObjectAdaptor::UDBusPrivate::FuncStub_UnRegister,
UDbusObjectAdaptor::UDBusPrivate::FuncStub_Message,
nullptr, nullptr, nullptr, nullptr
};
typedef std::map<Path, UDbusObjectAdaptor *> UDbusObjectAdaptorTable;
static UDbusObjectAdaptorTable sAdaptorTable;
void UDbusObjectAdaptor::UDBusPrivate::FuncStub_UnRegister(DBusConnection *conn, void *data)
{
}
DBusHandlerResult UDbusObjectAdaptor::UDBusPrivate::FuncStub_Message(DBusConnection *, DBusMessage *dbusmsg, void *data)
{
UDbusObjectAdaptor *obj = static_cast<UDbusObjectAdaptor *>(data);
if (obj)
{
Message message(new Message::UDBusPrivate(dbusmsg));
ERROR("%s serial:%d %s -> %s", obj->GetPath().c_str(), message.Serial(),
message.Sender(), message.Destination());
return obj->HandleMessage(message) ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
else
{
ERROR("no obj registered")
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
}
UDbusObjectAdaptor *UDbusObjectAdaptor::FromPath(const UDBus::Path &path)
{
UDbusObjectAdaptorTable::iterator adapti = sAdaptorTable.find(path);
if (adapti != sAdaptorTable.end())
return adapti->second;
return nullptr;
}
UDbusObjectAdaptorPList UDbusObjectAdaptor::FromPathPrefix(const std::string &prefix)
{
UDbusObjectAdaptorPList ali;
UDbusObjectAdaptorTable::iterator adapti = sAdaptorTable.begin();
size_t plen = prefix.length();
while (adapti != sAdaptorTable.end()) {
if (!strncmp(adapti->second->GetPath().c_str(), prefix.c_str(), plen))
ali.push_back(adapti->second);
++adapti;
}
return ali;
}
ObjectPathList UDbusObjectAdaptor::ChildNodesFromPrefix(const std::string &prefix)
{
ObjectPathList objPathlist;
UDbusObjectAdaptorTable::iterator iter = sAdaptorTable.begin();
size_t plen = prefix.length();
while (iter != sAdaptorTable.end())
{
if (iter->second->GetPath() != "/" &&
!strncmp(iter->second->GetPath().c_str(), prefix.c_str(), plen))
{
std::string path = iter->second->GetPath().substr(plen);
path = path.substr(0, path.find('/'));
objPathlist.push_back(path);
}
++iter;
}
objPathlist.sort();
objPathlist.unique();
return objPathlist;
}
UDbusObjectAdaptor::UDbusObjectAdaptor(Connection &Connection, const UDBus::Path &path)
: Object(Connection, path, Connection.UniqueName()), mEflag(USE_EXCEPTIONS)
{
RegisterObj();
}
UDbusObjectAdaptor::UDbusObjectAdaptor(Connection &Connection, const UDBus::Path &path, RegistrationTime rtime)
: Object(Connection, path, Connection.UniqueName()), mEflag(USE_EXCEPTIONS)
{
if (rtime == REGISTER_NOW)
RegisterObj();
}
UDbusObjectAdaptor::UDbusObjectAdaptor(Connection &Connection, const UDBus::Path &path, RegistrationTime rtime, ExceptionsFlag eflag)
: Object(Connection, path, Connection.UniqueName()), mEflag(eflag)
{
if (rtime == REGISTER_NOW)
RegisterObj();
}
UDbusObjectAdaptor::~UDbusObjectAdaptor()
{
try
{
UnRegisterObj();
}
catch(UDBusError &e)
{
DEBUG("Error{%s}", e.what());
}
}
void UDbusObjectAdaptor::RegisterObj()
{
DEBUG("registering local object %s", GetPath().c_str());
if (GetConn().mPrivate->Connection == nullptr)
{
throw ErrorInvalidArgs("nullptr connection");
}
else if (GetPath().c_str() == nullptr)
{
throw ErrorInvalidArgs("nullptr path");
}
else if (GetPath().c_str()[0] != '/')
{
std::string message = "Path must start with '/': " + GetPath();
throw ErrorInvalidArgs(message.c_str());
}
DBusError error = DBUS_ERROR_INIT;
if (!dbus_connection_try_register_object_path(
GetConn().mPrivate->Connection, GetPath().c_str(), &_vtable, this,
&error))
{
if (dbus_error_has_name(&error, DBUS_ERROR_OBJECT_PATH_IN_USE))
{
dbus_error_free(&error);
throw ErrorObjectPathInUse("unable to register object path");
}
else
{
dbus_error_free(&error);
throw ErrorNoMemory("unable to register object path");
}
}
sAdaptorTable[GetPath()] = this;
}
void UDbusObjectAdaptor::UnRegisterObj()
{
if (!IsRegistered())
return;
sAdaptorTable.erase(GetPath());
DEBUG("unregistering local object %s", GetPath().c_str());
if (GetConn().mPrivate->Connection == nullptr) {
throw ErrorInvalidArgs("nullptr connection");
} else if (GetPath().c_str() == nullptr) {
throw ErrorInvalidArgs("nullptr path");
} else if (GetPath().c_str()[0] != '/') {
std::string message = "Path must start with '/': " + GetPath();
throw ErrorInvalidArgs(message.c_str());
}
dbus_connection_unregister_object_path(GetConn().mPrivate->Connection, GetPath().c_str());
}
bool UDbusObjectAdaptor::IsRegistered()
{
return sAdaptorTable.find(GetPath()) != sAdaptorTable.end();
}
void UDbusObjectAdaptor::EmitSignalInternal(SignalMessage &sig)
{
sig.SetPath(GetPath().c_str());
GetConn().Send(sig);
}
struct UDbusReturnLaterError {
const UDBus::Tag *tag;
};
// for dbus method_call message
bool UDbusObjectAdaptor::HandleMessage(const Message &msg)
{
switch (msg.Type()) {
case DBUS_MESSAGE_TYPE_METHOD_CALL: {
const CallMessage &cmsg = reinterpret_cast<const CallMessage &>(msg);
const char* member = cmsg.GetMember();
const char* interface = cmsg.GetInterface();
DEBUG(" invoking method %s.%s", interface, member);
UDbusInterfaceAdaptor *interfaceProxy = FindInterface(interface);
if (interfaceProxy) {
if (mEflag == AVOID_EXCEPTIONS) {
Message ret = interfaceProxy->DispatchMethod(cmsg);
if (cmsg.isSync == false)
return true;
Tag *tag = ret.GetTag();
if (tag) {
mContinuations[tag] =
new UDbusContinuation(GetConn(), cmsg, tag);
} else {
GetConn().Send(ret);
}
return true;
}
try {
Message ret = interfaceProxy->DispatchMethod(cmsg);
if (cmsg.isSync == false)
{
return true;
}
GetConn().Send(ret);
} catch(UDBusError &e) {
UDbusErrorMessage em(cmsg, e.GetName(), e.message());
GetConn().Send(em);
} catch(UDbusReturnLaterError &UDbusRle) {
mContinuations[UDbusRle.tag] = new UDbusContinuation(GetConn(), cmsg, UDbusRle.tag);
}
return true;
} else {
return false;
}
}
default: return false;
}
}
void UDbusObjectAdaptor::ReturnLater(const UDBus::Tag *tag)
{
UDbusReturnLaterError rle = { tag };
throw rle;
}
void UDbusObjectAdaptor::ReturnNow(UDbusContinuation *ret)
{
ret->mConn.Send(ret->mReturn);
ContinuationMap::iterator di = mContinuations.find(ret->mTag);
delete di->second;
mContinuations.erase(di);
}
void UDbusObjectAdaptor::ReturnError(UDbusContinuation *ret, const UDBusError error)
{
ret->mConn.Send(UDbusErrorMessage(ret->mCall, error.GetName(), error.message()));
ContinuationMap::iterator di = mContinuations.find(ret->mTag);
delete di->second;
mContinuations.erase(di);
}
bool UDbusObjectAdaptor::ReplyAsyncMessage(const CallMessage & cmsg, const Message &msg)
{
try {
GetConn().Send(msg);
} catch(UDBusError &e) {
UDbusErrorMessage em(msg, e.GetName(), e.message());
GetConn().Send(em);
} catch(UDbusReturnLaterError &UDbusRle) {
mContinuations[UDbusRle.tag] = new UDbusContinuation(GetConn(), cmsg, UDbusRle.tag);
}
return true;
}
UDbusObjectAdaptor::UDbusContinuation *UDbusObjectAdaptor::FindContinuation(const UDBus::Tag *tag)
{
ContinuationMap::iterator di = mContinuations.find(tag);
return di != mContinuations.end() ? di->second : nullptr;
}
UDbusObjectAdaptor::UDbusContinuation::UDbusContinuation(Connection &Connection, const CallMessage &call, const UDBus::Tag *tag)
: mConn(Connection), mCall(call), mReturn(mCall), mTag(tag)
{
mWriter = mReturn.Writer();
}
UDbusObjectProxy::UDbusObjectProxy(Connection &Connection, const UDBus::Path &path, const char *service)
: Object(Connection, path, service)
{
RegisterObj();
}
UDbusObjectProxy::~UDbusObjectProxy()
{
CancelPendingCalls();
try
{
UnRegisterObj();
}
catch(UDBusError &e)
{
DEBUG("Error{%s}", e.what());
}
}
void UDbusObjectProxy::CancelPendingCalls()
{
PendingCallList::const_iterator pi = mPendingCalls.begin();
while (pi != mPendingCalls.end()) {
(*pi)->Cancel();
delete *pi;
++pi;
}
mPendingCalls.clear();
}
void UDbusObjectProxy::_RemovePendingCall(PendingCall *pending)
{
PendingCallList::iterator iter = mPendingCalls.begin();
while (iter != mPendingCalls.end()) {
if (pending == *iter) {
mPendingCalls.erase(iter);
break;
}
++iter;
}
delete pending;
}
bool UDbusObjectProxy::IsRegistered()
{
return true;
}
void UDbusObjectProxy::RegisterObj()
{
DEBUG("registering remote object %s", GetPath().c_str());
mFiltered = new Callback<UDbusObjectProxy, bool, const Message &>(this, &UDbusObjectProxy::HandleMessage);
GetConn().AddFilter(mFiltered);
InterfaceProxyTable::const_iterator interfaceProxy = mInterfaces.begin();
while (interfaceProxy != mInterfaces.end()) {
std::string im = "type='signal',interface='" + interfaceProxy->first + "',path='" + GetPath() + "'";
GetConn().AddMatch(im.c_str());
++interfaceProxy;
}
DEBUG("");
}
void UDbusObjectProxy::UnRegisterObj()
{
DEBUG("unregistering remote object %s", GetPath().c_str());
InterfaceProxyTable::const_iterator interfaceProxy = mInterfaces.begin();
while (interfaceProxy != mInterfaces.end()) {
std::string im = "type='signal',interface='" + interfaceProxy->first + "',path='" + GetPath() + "'";
GetConn().RmoveMatch(im.c_str());
++interfaceProxy;
}
GetConn().RemoveFilter(mFiltered);
}
Message UDbusObjectProxy::_InvokeMethod(CallMessage &call)
{
if (call.GetPath() == nullptr)
call.SetPath(GetPath().c_str());
if (call.Destination() == nullptr)
call.SetDestination(GetService().c_str());
return GetConn().SendBlocking(call);
}
Message UDbusObjectProxy::_InvokeMethodWaitTime(CallMessage &call, int timeout)
{
if (call.GetPath() == nullptr)
call.SetPath(GetPath().c_str());
if (call.Destination() == nullptr)
call.SetDestination(GetService().c_str());
return GetConn().SendBlocking(call, timeout);
}
bool UDbusObjectProxy::_InvokeMethodNoReply(CallMessage &call)
{
if (call.GetPath() == nullptr)
call.SetPath(GetPath().c_str());
if (call.Destination() == nullptr)
call.SetDestination(GetService().c_str());
return GetConn().Send(call);
}
// for dbus signal message
bool UDbusObjectProxy::HandleMessage(const Message &msg)
{
switch (msg.Type()) {
case DBUS_MESSAGE_TYPE_SIGNAL: {
const SignalMessage &smsg = reinterpret_cast<const SignalMessage &>(msg);
const char* interface = smsg.GetInterface();
const char* member = smsg.GetMember();
const char* objpath = smsg.GetPath();
if (objpath != GetPath()) return false;
ERROR("filtered signal %s(in %s) from %s to object %s", member, interface, msg.Sender(), objpath);
InterfaceProxy* interfaceProxy = FindInterface(interface);
if (interfaceProxy) {
bool done = true;
try
{
done = interfaceProxy->DispatchSignal(smsg);
}
catch(UDBusError &e)
{
ERROR("Error{%s}", e.what());
done = true;
}
return done;
} else {
ERROR("interfaceProxy is null return false");
return false;
}
}
default:
return false;
}
}
PendingCall *UDbusObjectProxy::_InvokeMethodAsync(CallMessage &call, int timeout)
{
if (call.GetPath() == nullptr)
call.SetPath(GetPath().c_str());
if (call.Destination() == nullptr)
call.SetDestination(GetService().c_str());
PendingCall *pending = GetConn().SendAsync(call, timeout);
mPendingCalls.push_back(pending);
return pending;
}