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