Loading CMakeLists.txt +1 −0 Changes for CMakeLists.txt: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ configure_file(config.h.in ${CMAKE_BINARY_DIR}/config.h) add_library(sysbus STATIC src/sysbus/message.cpp src/sysbus/client.cpp src/sysbus/service.cpp ) target_include_directories(sysbus PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> Loading include/sysbus/client.h +18 −0 Changes for include/sysbus/client.h: 18 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -36,6 +36,12 @@ constexpr const char *Subscribe = "Subscribe"; constexpr const char *Reboot = "Reboot"; constexpr const char *PowerOff = "PowerOff"; // Services: other daemons register a name (root only, see sysbus/service.h); // a call with the field "sysbus.destination" set to that name is forwarded // to the daemon and its reply passed back (Client::callService()). constexpr const char *RegisterService = "RegisterService"; // name constexpr const char *ListServices = "ListServices"; // -> service, service_pid (repeated) // Network interfaces. Configurations are .network files in // /etc/syslite/network; Create/Edit/Delete change only the files, Start, // Reload and Restart apply them. Loading Loading @@ -66,6 +72,9 @@ constexpr const char *UnknownInterface = "sysbus.Error.UnknownInterface"; constexpr const char *AccessDenied = "sysbus.Error.AccessDenied"; constexpr const char *Failed = "sysbus.Error.Failed"; constexpr const char *InvalidArgs = "sysbus.Error.InvalidArgs"; constexpr const char *ServiceUnknown = "sysbus.Error.ServiceUnknown"; // no such service registered constexpr const char *ServiceGone = "sysbus.Error.ServiceGone"; // it went away before replying constexpr const char *Timeout = "sysbus.Error.Timeout"; // it didn't reply in time } // namespace error struct UnitInfo { Loading Loading @@ -136,6 +145,15 @@ public: const std::vector<std::pair<std::string, std::string>> &args = {}, int timeoutMs = 90000); // A method of a registered service (forwarded by the bus, see // sysbus/service.h). Errors as for call(); an unknown service is // sysbus.Error.ServiceUnknown. Message callService(const std::string &service, const std::string &member, const std::vector<std::pair<std::string, std::string>> &args = {}, int timeoutMs = 90000); // The registered services' names. std::vector<std::string> listServices(); // Unit control: true on success, otherwise see lastError(). bool startUnit(const std::string &name); bool stopUnit(const std::string &name); Loading include/sysbus/service.h 0 → 100644 +65 −0 Changes for include/sysbus/service.h: 65 added lines, 0 removed lines. Original line number Diff line number Diff line #pragma once // A daemon that offers methods on sysbus under a name of its own: // // sysbus::Service svc; // svc.start("sharedd", [](const sysbus::Message &call, const sysbus::Caller &who) { // if (call.member == "ListShares") ... // return sysbus::Message::reply(call); // }); // // in the main loop: poll(svc.fd(), POLLIN) and then svc.process() // // Registering needs root (the bus only takes names from uid 0); callers // reach it with Client::callService("sharedd", ...). Each call carries the // caller's uid and pid as the bus saw them (SO_PEERCRED), so a service can // refuse changes from non-root callers. When the bus goes away (syslite // restarts), process() returns false and start() can be called again. #include "sysbus/message.h" #include <functional> #include <string> #include <sys/types.h> namespace sysbus { struct Caller { uid_t uid = static_cast<uid_t>(-1); pid_t pid = -1; }; class Service { public: // Returns the reply: Message::reply(call) or Message::error(call, ...). using Handler = std::function<Message(const Message &call, const Caller &caller)>; Service() = default; ~Service(); Service(const Service &) = delete; Service &operator=(const Service &) = delete; bool start(const std::string &name, Handler handler, const std::string &path = SYSBUS_SOCKET); void stop(); bool running() const { return _fd >= 0; } int fd() const { return _fd; } // Reads what arrived and answers the calls in it. false once the bus // connection is gone. bool process(); // A signal to every subscribed client (the bus adds "sysbus.sender"). bool emit(const std::string &signal, const std::vector<std::pair<std::string, std::string>> &fields = {}); const std::string &name() const { return _name; } const std::string &lastError() const { return _lastError; } private: int _fd = -1; uint32_t _serial = 0; std::string _name; Handler _handler; Decoder _decoder; std::string _lastError; }; } // namespace sysbus src/busserver.h +18 −0 Changes for src/busserver.h: 18 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -47,12 +47,30 @@ private: void accept(); void serve(int fd); void drop(int fd); // false if fd was dropped bool send(int fd, const sysbus::Message &msg); sysbus::Message busMethod(const sysbus::Message &call, int fd, BusPeer &peer, bool &handled); void route(const sysbus::Message &call, int fd, const BusPeer &peer, const std::string &dest); void answer(const sysbus::Message &reply, int fd); void expirePending(); // a call forwarded to a service, waiting for its reply struct Pending { int callerFd; uint32_t callerSerial; int serviceFd; long sentMs; }; static constexpr long ServiceTimeoutMs = 120000; int _listenFd = -1; std::string _path; Handler _handler; std::map<int, Client> _clients; uint32_t _signalSerial = 0; std::map<std::string, int> _services; // name -> fd std::map<uint32_t, Pending> _pending; // bus serial -> caller uint32_t _forwardSerial = 0; }; } // namespace syslite src/sysbus/client.cpp +15 −0 Changes for src/sysbus/client.cpp: 15 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -161,6 +161,21 @@ Message Client::call(const std::string &member, } } Message Client::callService(const std::string &service, const std::string &member, const std::vector<std::pair<std::string, std::string>> &args, int timeoutMs) { std::vector<std::pair<std::string, std::string>> all; all.reserve(args.size() + 1); all.emplace_back("sysbus.destination", service); all.insert(all.end(), args.begin(), args.end()); return call(member, all, timeoutMs); } std::vector<std::string> Client::listServices() { Message r; if (!checkedCall(method::ListServices, {}, &r)) return {}; return r.getAll("service"); } bool Client::simpleCall(const char *member, const std::string &unit) { Message r = call(member, {{"unit", unitName(unit)}}); if (r.type == MessageType::Error) { Loading Loading
CMakeLists.txt +1 −0 Changes for CMakeLists.txt: 1 added line, 0 removed lines. Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ configure_file(config.h.in ${CMAKE_BINARY_DIR}/config.h) add_library(sysbus STATIC src/sysbus/message.cpp src/sysbus/client.cpp src/sysbus/service.cpp ) target_include_directories(sysbus PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> Loading
include/sysbus/client.h +18 −0 Changes for include/sysbus/client.h: 18 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -36,6 +36,12 @@ constexpr const char *Subscribe = "Subscribe"; constexpr const char *Reboot = "Reboot"; constexpr const char *PowerOff = "PowerOff"; // Services: other daemons register a name (root only, see sysbus/service.h); // a call with the field "sysbus.destination" set to that name is forwarded // to the daemon and its reply passed back (Client::callService()). constexpr const char *RegisterService = "RegisterService"; // name constexpr const char *ListServices = "ListServices"; // -> service, service_pid (repeated) // Network interfaces. Configurations are .network files in // /etc/syslite/network; Create/Edit/Delete change only the files, Start, // Reload and Restart apply them. Loading Loading @@ -66,6 +72,9 @@ constexpr const char *UnknownInterface = "sysbus.Error.UnknownInterface"; constexpr const char *AccessDenied = "sysbus.Error.AccessDenied"; constexpr const char *Failed = "sysbus.Error.Failed"; constexpr const char *InvalidArgs = "sysbus.Error.InvalidArgs"; constexpr const char *ServiceUnknown = "sysbus.Error.ServiceUnknown"; // no such service registered constexpr const char *ServiceGone = "sysbus.Error.ServiceGone"; // it went away before replying constexpr const char *Timeout = "sysbus.Error.Timeout"; // it didn't reply in time } // namespace error struct UnitInfo { Loading Loading @@ -136,6 +145,15 @@ public: const std::vector<std::pair<std::string, std::string>> &args = {}, int timeoutMs = 90000); // A method of a registered service (forwarded by the bus, see // sysbus/service.h). Errors as for call(); an unknown service is // sysbus.Error.ServiceUnknown. Message callService(const std::string &service, const std::string &member, const std::vector<std::pair<std::string, std::string>> &args = {}, int timeoutMs = 90000); // The registered services' names. std::vector<std::string> listServices(); // Unit control: true on success, otherwise see lastError(). bool startUnit(const std::string &name); bool stopUnit(const std::string &name); Loading
include/sysbus/service.h 0 → 100644 +65 −0 Changes for include/sysbus/service.h: 65 added lines, 0 removed lines. Original line number Diff line number Diff line #pragma once // A daemon that offers methods on sysbus under a name of its own: // // sysbus::Service svc; // svc.start("sharedd", [](const sysbus::Message &call, const sysbus::Caller &who) { // if (call.member == "ListShares") ... // return sysbus::Message::reply(call); // }); // // in the main loop: poll(svc.fd(), POLLIN) and then svc.process() // // Registering needs root (the bus only takes names from uid 0); callers // reach it with Client::callService("sharedd", ...). Each call carries the // caller's uid and pid as the bus saw them (SO_PEERCRED), so a service can // refuse changes from non-root callers. When the bus goes away (syslite // restarts), process() returns false and start() can be called again. #include "sysbus/message.h" #include <functional> #include <string> #include <sys/types.h> namespace sysbus { struct Caller { uid_t uid = static_cast<uid_t>(-1); pid_t pid = -1; }; class Service { public: // Returns the reply: Message::reply(call) or Message::error(call, ...). using Handler = std::function<Message(const Message &call, const Caller &caller)>; Service() = default; ~Service(); Service(const Service &) = delete; Service &operator=(const Service &) = delete; bool start(const std::string &name, Handler handler, const std::string &path = SYSBUS_SOCKET); void stop(); bool running() const { return _fd >= 0; } int fd() const { return _fd; } // Reads what arrived and answers the calls in it. false once the bus // connection is gone. bool process(); // A signal to every subscribed client (the bus adds "sysbus.sender"). bool emit(const std::string &signal, const std::vector<std::pair<std::string, std::string>> &fields = {}); const std::string &name() const { return _name; } const std::string &lastError() const { return _lastError; } private: int _fd = -1; uint32_t _serial = 0; std::string _name; Handler _handler; Decoder _decoder; std::string _lastError; }; } // namespace sysbus
src/busserver.h +18 −0 Changes for src/busserver.h: 18 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -47,12 +47,30 @@ private: void accept(); void serve(int fd); void drop(int fd); // false if fd was dropped bool send(int fd, const sysbus::Message &msg); sysbus::Message busMethod(const sysbus::Message &call, int fd, BusPeer &peer, bool &handled); void route(const sysbus::Message &call, int fd, const BusPeer &peer, const std::string &dest); void answer(const sysbus::Message &reply, int fd); void expirePending(); // a call forwarded to a service, waiting for its reply struct Pending { int callerFd; uint32_t callerSerial; int serviceFd; long sentMs; }; static constexpr long ServiceTimeoutMs = 120000; int _listenFd = -1; std::string _path; Handler _handler; std::map<int, Client> _clients; uint32_t _signalSerial = 0; std::map<std::string, int> _services; // name -> fd std::map<uint32_t, Pending> _pending; // bus serial -> caller uint32_t _forwardSerial = 0; }; } // namespace syslite
src/sysbus/client.cpp +15 −0 Changes for src/sysbus/client.cpp: 15 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -161,6 +161,21 @@ Message Client::call(const std::string &member, } } Message Client::callService(const std::string &service, const std::string &member, const std::vector<std::pair<std::string, std::string>> &args, int timeoutMs) { std::vector<std::pair<std::string, std::string>> all; all.reserve(args.size() + 1); all.emplace_back("sysbus.destination", service); all.insert(all.end(), args.begin(), args.end()); return call(member, all, timeoutMs); } std::vector<std::string> Client::listServices() { Message r; if (!checkedCall(method::ListServices, {}, &r)) return {}; return r.getAll("service"); } bool Client::simpleCall(const char *member, const std::string &unit) { Message r = call(member, {{"unit", unitName(unit)}}); if (r.type == MessageType::Error) { Loading