summaryrefslogtreecommitdiffstats
path: root/include/ipmid/filter.hpp
blob: 950e3c3f255a207f77827ba52271945f4f388ef9 (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
/**
 * Copyright © 2018 Intel Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#pragma once
#include <algorithm>
#include <boost/callable_traits.hpp>
#include <cstdint>
#include <ipmid/api-types.hpp>
#include <ipmid/message.hpp>
#include <memory>
#include <tuple>
#include <utility>

namespace ipmi
{

using FilterFunction = ipmi::Cc(ipmi::message::Request::ptr);

/**
 * @brief Filter base class for dealing with IPMI request/response
 *
 * The subclasses are all templated so they can provide access to any type of
 * command callback functions.
 */
class FilterBase
{
  public:
    using ptr = std::shared_ptr<FilterBase>;

    virtual ipmi::Cc call(message::Request::ptr request) = 0;
};

/**
 * @brief filter concrete class
 *
 * This is the base template that ipmi filters will resolve into. This is
 * essentially just a wrapper to hold the filter callback so it can be stored in
 * the filter list.
 *
 * Filters are called with a ipmi::message::Request shared_ptr on all IPMI
 * commands in priority order and each filter has the opportunity to reject the
 * command (by returning an IPMI error competion code.) If all the filters
 * return success, the actual IPMI command will be executed. Filters can reject
 * the command for any reason, based on system state, the context, the command
 * payload, etc.
 */
template <typename Filter>
class IpmiFilter : public FilterBase
{
  public:
    IpmiFilter(Filter&& filter) : filter_(std::move(filter))
    {
    }

    ipmi::Cc call(message::Request::ptr request) override
    {
        return filter_(request);
    }

  private:
    Filter filter_;
};

/**
 * @brief helper function to construct a filter object
 *
 * This is called internally by the ipmi::registerFilter function.
 */
template <typename Filter>
static inline auto makeFilter(Filter&& filter)
{
    FilterBase::ptr ptr(new IpmiFilter<Filter>(std::forward<Filter>(filter)));
    return ptr;
}
template <typename Filter>
static inline auto makeFilter(const Filter& filter)
{
    Filter lFilter = filter;
    return makeFilter(std::forward<Filter>(lFilter));
}

namespace impl
{

// IPMI command filter registration implementation
void registerFilter(int prio, ::ipmi::FilterBase::ptr filter);

} // namespace impl

/**
 * @brief IPMI command filter registration function
 *
 * This function should be used to register IPMI command filter functions.
 * This function just passes the callback to makeFilter, which creates a
 * wrapper functor object that ultimately calls the callback.
 *
 * Filters are called with a ipmi::message::Request shared_ptr on all IPMI
 * commands in priority order and each filter has the opportunity to reject the
 * command (by returning an IPMI error competion code.) If all the filters
 * return success, the actual IPMI command will be executed. Filters can reject
 * the command for any reason, based on system state, the context, the command
 * payload, etc.
 *
 * @param prio - priority at which to register; see api.hpp
 * @param filter - the callback function that will handle this request
 *
 * @return bool - success of registering the handler
 */
template <typename Filter>
void registerFilter(int prio, Filter&& filter)
{
    auto f = ipmi::makeFilter(std::forward<Filter>(filter));
    impl::registerFilter(prio, f);
}

template <typename Filter>
void registerFilter(int prio, const Filter& filter)
{
    auto f = ipmi::makeFilter(filter);
    impl::registerFilter(prio, f);
}

} // namespace ipmi
OpenPOWER on IntegriCloud