summaryrefslogtreecommitdiffstats
path: root/src/processing.cpp
blob: 6dd649365319307ccc54470a3abea11e8be3c7d0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#include "processing.hpp"

#include <boost/algorithm/string/predicate.hpp>
#include <iostream>

bool getWellKnown(
    const boost::container::flat_map<std::string, std::string>& owners,
    const std::string& request, std::string& wellKnown)
{
    // If it's already a well known name, just return
    if (!boost::starts_with(request, ":"))
    {
        wellKnown = request;
        return true;
    }

    auto it = owners.find(request);
    if (it == owners.end())
    {
        return false;
    }
    wellKnown = it->second;
    return true;
}

bool needToIntrospect(const std::string& processName,
                      const WhiteBlackList& whiteList,
                      const WhiteBlackList& blackList)
{
    auto inWhitelist =
        std::find_if(whiteList.begin(), whiteList.end(),
                     [&processName](const auto& prefix) {
                         return boost::starts_with(processName, prefix);
                     }) != whiteList.end();

    // This holds full service names, not prefixes
    auto inBlacklist = blackList.find(processName) != blackList.end();

    return inWhitelist && !inBlacklist;
}

void processNameChangeDelete(
    boost::container::flat_map<std::string, std::string>& nameOwners,
    const std::string& wellKnown, const std::string& oldOwner,
    interface_map_type& interfaceMap, AssociationOwnersType& assocOwners,
    AssociationInterfaces& assocInterfaces,
    sdbusplus::asio::object_server& server)
{
    if (boost::starts_with(oldOwner, ":"))
    {
        auto it = nameOwners.find(oldOwner);
        if (it != nameOwners.end())
        {
            nameOwners.erase(it);
        }
    }
    // Connection removed
    interface_map_type::iterator pathIt = interfaceMap.begin();
    while (pathIt != interfaceMap.end())
    {
        // If an associations interface is being removed,
        // also need to remove the corresponding associations
        // objects and properties.
        auto ifaces = pathIt->second.find(wellKnown);
        if (ifaces != pathIt->second.end())
        {
            auto assoc = std::find(ifaces->second.begin(), ifaces->second.end(),
                                   ASSOCIATIONS_INTERFACE);
            if (assoc != ifaces->second.end())
            {
                removeAssociation(pathIt->first, wellKnown, server, assocOwners,
                                  assocInterfaces);
            }
        }
        pathIt->second.erase(wellKnown);
        if (pathIt->second.empty())
        {
            // If the last connection to the object is gone,
            // delete the top level object
            pathIt = interfaceMap.erase(pathIt);
            continue;
        }
        pathIt++;
    }
}

void processInterfaceAdded(interface_map_type& interfaceMap,
                           const sdbusplus::message::object_path& objPath,
                           const InterfacesAdded& intfAdded,
                           const std::string& wellKnown,
                           AssociationOwnersType& assocOwners,
                           AssociationInterfaces& assocInterfaces,
                           sdbusplus::asio::object_server& server)
{
    auto& ifaceList = interfaceMap[objPath.str];

    for (const auto& interfacePair : intfAdded)
    {
        ifaceList[wellKnown].emplace(interfacePair.first);

        if (interfacePair.first == ASSOCIATIONS_INTERFACE)
        {
            const sdbusplus::message::variant<std::vector<Association>>*
                variantAssociations = nullptr;
            for (const auto& interface : interfacePair.second)
            {
                if (interface.first == "associations")
                {
                    variantAssociations = &(interface.second);
                }
            }
            if (variantAssociations == nullptr)
            {
                std::cerr << "Illegal association found on " << wellKnown
                          << "\n";
                continue;
            }
            std::vector<Association> associations =
                sdbusplus::message::variant_ns::get<std::vector<Association>>(
                    *variantAssociations);
            associationChanged(server, associations, objPath.str, wellKnown,
                               assocOwners, assocInterfaces);
        }
    }

    // To handle the case where an object path is being created
    // with 2 or more new path segments, check if the parent paths
    // of this path are already in the interface map, and add them
    // if they aren't with just the default freedesktop interfaces.
    // This would be done via introspection if they would have
    // already existed at startup.  While we could also introspect
    // them now to do the work, we know there aren't any other
    // interfaces or we would have gotten signals for them as well,
    // so take a shortcut to speed things up.
    //
    // This is all needed so that mapper operations can be done
    // on the new parent paths.
    using iface_map_iterator = interface_map_type::iterator;
    using iface_map_value_type =
        boost::container::flat_map<std::string,
                                   boost::container::flat_set<std::string>>;
    using name_map_iterator = iface_map_value_type::iterator;

    static const boost::container::flat_set<std::string> defaultIfaces{
        "org.freedesktop.DBus.Introspectable", "org.freedesktop.DBus.Peer",
        "org.freedesktop.DBus.Properties"};

    std::string parent = objPath.str;
    auto pos = parent.find_last_of('/');

    while (pos != std::string::npos)
    {
        parent = parent.substr(0, pos);

        std::pair<iface_map_iterator, bool> parentEntry =
            interfaceMap.insert(std::make_pair(parent, iface_map_value_type{}));

        std::pair<name_map_iterator, bool> ifaceEntry =
            parentEntry.first->second.insert(
                std::make_pair(wellKnown, defaultIfaces));

        if (!ifaceEntry.second)
        {
            // Entry was already there for this name so done.
            break;
        }

        pos = parent.find_last_of('/');
    }
}
OpenPOWER on IntegriCloud