/* * 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 #include #include #include #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::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(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(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(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 &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; }