1 /**
2  * Copyright © 2018 Intel Corporation
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 #pragma once
17 #include <algorithm>
18 #include <boost/callable_traits.hpp>
19 #include <cstdint>
20 #include <ipmid/api-types.hpp>
21 #include <ipmid/message.hpp>
22 #include <memory>
23 #include <tuple>
24 #include <utility>
25 
26 namespace ipmi
27 {
28 
29 using FilterFunction = ipmi::Cc(ipmi::message::Request::ptr);
30 
31 /**
32  * @brief Filter base class for dealing with IPMI request/response
33  *
34  * The subclasses are all templated so they can provide access to any type of
35  * command callback functions.
36  */
37 class FilterBase
38 {
39   public:
40     using ptr = std::shared_ptr<FilterBase>;
41 
42     virtual ~FilterBase() = default;
43 
44     virtual ipmi::Cc call(message::Request::ptr request) = 0;
45 };
46 
47 /**
48  * @brief filter concrete class
49  *
50  * This is the base template that ipmi filters will resolve into. This is
51  * essentially just a wrapper to hold the filter callback so it can be stored in
52  * the filter list.
53  *
54  * Filters are called with a ipmi::message::Request shared_ptr on all IPMI
55  * commands in priority order and each filter has the opportunity to reject the
56  * command (by returning an IPMI error competion code.) If all the filters
57  * return success, the actual IPMI command will be executed. Filters can reject
58  * the command for any reason, based on system state, the context, the command
59  * payload, etc.
60  */
61 template <typename Filter>
62 class IpmiFilter : public FilterBase
63 {
64   public:
65     IpmiFilter(Filter&& filter) : filter_(std::move(filter))
66     {
67     }
68 
69     ipmi::Cc call(message::Request::ptr request) override
70     {
71         return filter_(request);
72     }
73 
74   private:
75     Filter filter_;
76 };
77 
78 /**
79  * @brief helper function to construct a filter object
80  *
81  * This is called internally by the ipmi::registerFilter function.
82  */
83 template <typename Filter>
84 static inline auto makeFilter(Filter&& filter)
85 {
86     FilterBase::ptr ptr(new IpmiFilter<Filter>(std::forward<Filter>(filter)));
87     return ptr;
88 }
89 template <typename Filter>
90 static inline auto makeFilter(const Filter& filter)
91 {
92     Filter lFilter = filter;
93     return makeFilter(std::forward<Filter>(lFilter));
94 }
95 
96 namespace impl
97 {
98 
99 // IPMI command filter registration implementation
100 void registerFilter(int prio, ::ipmi::FilterBase::ptr filter);
101 
102 } // namespace impl
103 
104 /**
105  * @brief IPMI command filter registration function
106  *
107  * This function should be used to register IPMI command filter functions.
108  * This function just passes the callback to makeFilter, which creates a
109  * wrapper functor object that ultimately calls the callback.
110  *
111  * Filters are called with a ipmi::message::Request shared_ptr on all IPMI
112  * commands in priority order and each filter has the opportunity to reject the
113  * command (by returning an IPMI error competion code.) If all the filters
114  * return success, the actual IPMI command will be executed. Filters can reject
115  * the command for any reason, based on system state, the context, the command
116  * payload, etc.
117  *
118  * @param prio - priority at which to register; see api.hpp
119  * @param filter - the callback function that will handle this request
120  *
121  * @return bool - success of registering the handler
122  */
123 template <typename Filter>
124 void registerFilter(int prio, Filter&& filter)
125 {
126     auto f = ipmi::makeFilter(std::forward<Filter>(filter));
127     impl::registerFilter(prio, f);
128 }
129 
130 template <typename Filter>
131 void registerFilter(int prio, const Filter& filter)
132 {
133     auto f = ipmi::makeFilter(filter);
134     impl::registerFilter(prio, f);
135 }
136 
137 } // namespace ipmi
138