1 /**
2  * Copyright 2017 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "lpcsnoop/snoop.hpp"
18 
19 #include <sdbusplus/bus.hpp>
20 #include <sdbusplus/bus/match.hpp>
21 #include <sdbusplus/message.hpp>
22 
23 namespace lpcsnoop
24 {
25 using std::get;
26 
27 /* Returns matching string for what signal to listen on Dbus */
GetMatchRule()28 static const std::string GetMatchRule()
29 {
30     using namespace sdbusplus::bus::match::rules;
31 
32     return type::signal() + interface("org.freedesktop.DBus.Properties") +
33            member("PropertiesChanged") + path(snoopObject);
34 }
35 
36 class SnoopListen
37 {
38     using message_handler_t = std::function<void(sdbusplus::message_t&)>;
39     using postcode_handler_t = std::function<void(FILE*, postcode_t)>;
40 
41   public:
SnoopListen(sdbusplus::bus_t & busIn,sd_bus_message_handler_t handler)42     SnoopListen(sdbusplus::bus_t& busIn, sd_bus_message_handler_t handler) :
43         signal(busIn, GetMatchRule().c_str(), handler, this)
44     {}
45 
SnoopListen(sdbusplus::bus_t & busIn,message_handler_t handler)46     SnoopListen(sdbusplus::bus_t& busIn, message_handler_t handler) :
47         signal(busIn, GetMatchRule(), handler)
48     {}
49 
SnoopListen(sdbusplus::bus_t & busIn,postcode_handler_t handler,FILE * f=NULL)50     SnoopListen(sdbusplus::bus_t& busIn, postcode_handler_t handler,
51                 FILE* f = NULL) :
52         SnoopListen(busIn, std::bind(defaultMessageHandler, handler, f,
53                                      std::placeholders::_1))
54     {}
55 
56     SnoopListen() = delete; // no default constructor
57     ~SnoopListen() = default;
58     SnoopListen(const SnoopListen&) = delete;
59     SnoopListen& operator=(const SnoopListen&) = delete;
60     SnoopListen(SnoopListen&&) = default;
61     SnoopListen& operator=(SnoopListen&&) = default;
62 
63   private:
64     sdbusplus::bus::match_t signal;
65 
66     /*
67      * Default message handler which listens to published messages on snoop
68      * DBus path, and calls the given postcode_handler on each value received.
69      */
defaultMessageHandler(postcode_handler_t & handler,FILE * f,sdbusplus::message_t & m)70     static void defaultMessageHandler(postcode_handler_t& handler, FILE* f,
71                                       sdbusplus::message_t& m)
72     {
73         std::string messageBusName;
74         std::map<std::string, std::variant<postcode_t>> messageData;
75         constexpr char propertyKey[] = "Value";
76 
77         m.read(messageBusName, messageData);
78 
79         if (messageBusName == snoopDbus &&
80             messageData.find(propertyKey) != messageData.end())
81         {
82             handler(f, get<postcode_t>(messageData[propertyKey]));
83         }
84     }
85 };
86 
87 } // namespace lpcsnoop
88